diff -u --recursive --new-file v2.3.16/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.3.16/linux/Documentation/Configure.help	Tue Aug 31 17:29:12 1999
+++ linux/Documentation/Configure.help	Tue Sep  7 11:23:40 1999
@@ -4835,8 +4835,8 @@
 
 AMI MegaRAID support
 CONFIG_SCSI_MEGARAID
-  This driver supports the AMI MegaRAID 428 and 438 (and maybe 466)
-  SCSI host adapters. 
+  This driver supports the AMI MegaRAID 418, 428, 438, 466, 762, 490
+  and 467 SCSI host adapters. 
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -6043,19 +6043,50 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called yellowfin.o.
 
+General Instruments Surfboard 1000
+CONFIG_NET_SB1000
+  This is a driver for the General Instrument SURFboard 1000 internal cable
+  modem.  This is an ISA card which is used by a number of cable TV companies
+  to provide cable modem access.  It's a one-way downstream-only cable modem,
+  meaning that your upstream net link is provided by your regular phone modem.
+
+  At present this driver only compiles as a module, so say M here if you
+  have this card.  Then read Documentation/networking/README.sb1000 for
+  information on how to use this module, as it needs special ppp scripts for
+  establishing a connection.  Further documentation and the necessary scripts
+  can be found at:
+
+  http://www.jacksonville.net/~fventuri/
+  http://home.adelphia.net/~siglercm/sb1000.html
+  http://linuxpower.cx/~cable/
+
+  If you don't have this card, of course say N.
+
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
-  Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
-  Ethernet adapter. The driver allows for using the Jumbo Frame
-  option (9000 bytes/frame) however it requires that your switches
-  can handle this as well. To enable Jumbo Frames, add `mtu 9000' to
-  your ifconfig line.
+  Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear
+  GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet
+  adapter. The driver allows for using the Jumbo Frame option (9000
+  bytes/frame) however it requires that your switches can handle this
+  as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig
+  line.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called acenic.o.
 
+Omit support for older Tigon I based AceNICs
+CONFIG_ACENIC_OMIT_TIGON_I
+  Say Y here if you only have Tigon II based AceNICs and want to leave
+  out support for the older Tigon I based cards which are no longer
+  being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B
+  version)). This will reduce the size of the driver object by
+  app. 100KB. If you are not sure whether your card is a Tigon I or a
+  Tigon II, say N here.
+
+  The safe and default value for this is N.
+
 AMD LANCE and PCnet (AT1500 and NE2100) support
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
@@ -7216,7 +7247,7 @@
   You don't want to use the minix filesystem on your hard disk because
   of certain built-in restrictions, but it is sometimes found on older
   Linux floppy disks. This option will enlarge your kernel by about 
-  25 kB. If unsure, say N.
+  28 kB. If unsure, say N.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -7242,7 +7273,7 @@
   ext2fs is a diskless Linux box which mounts all files over the
   network using NFS (in this case it's sufficient to say Y to "NFS
   filesystem support" below). Saying Y here will enlarge your kernel
-  by about 41 kB.
+  by about 44 kB.
 
   The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
   anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini,
@@ -7299,6 +7330,25 @@
   like lynx or netscape). Say Y here if you want to be able to read
   Joliet CDROMs under Linux.
 
+UDF Filesystem support
+CONFIG_UDF_FS
+  This is the new filesystem used by some CDROMS and DVD drivers. 
+  Say Y if you intend to mount DVD discs or CDRWs written in packet mode,
+  or if written to by other UDF utilities, such as DirectCD.
+
+  This filesystem support is also available as a module ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want). The module is called udf.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. 
+
+  If unsure, say N.
+
+UDF read-write support (EXPERIMENTAL)
+CONFIG_UDF_RW
+  Say Y if you want to test write support for UDF filesystems.
+  Due to lack of support for writing to CDR/CDRW's, this option
+  is only supported for Hard Discs, DVD-RAM, and loopback files.
+
 fat fs support
 CONFIG_FAT_FS
   If you want to use one of the FAT-based filesystems (the MS-DOS,
@@ -7430,7 +7480,7 @@
   that has a program like lynx or netscape), and also on the proc(8)
   manpage ("man 8 proc").
 
-  This option will enlarge your kernel by about 18 KB. Several
+  This option will enlarge your kernel by about 67 KB. Several
   programs depend on this, so everyone should say Y here.
 
 NFS filesystem support
@@ -7723,6 +7773,18 @@
   Say Y to this only if you plan on mounting disks with SGI disklabels.
   This is not required to mount EFS-format CDROMs.
 
+EFS filesystem support (experimental)
+CONFIG_EFS_FS
+  EFS is the filesystem used for CDROMs and filesystems by SGI's IRIX.
+  This implementation only offers read-only access.  If you don't know
+  what all this is about, it's safe to say N.  For more information
+  about EFS see it's homepage at http://aeschi.ch.eu.org/efs.
+
+SGI disklabel support
+CONFIG_SGI_DISKLABEL
+  Say Y to this only if you plan on mounting disks with SGI disklabels.
+  This is not required to mount EFS-format CDROMs.
+
 BSD disklabel (FreeBSD partition tables) support
 CONFIG_BSD_DISKLABEL
   FreeBSD uses its own hard disk partition scheme on your PC. It
@@ -8244,6 +8306,16 @@
   letters that were missing in Latin 4 to cover the entire Nordic
   area.
 
+nls iso8859-14
+CONFIG_NLS_ISO8859_14
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 8 character
+  set, which adds the last accented vowels for Welsh (and Manx Gaelic)
+  that were missing in Latin 1. http://linux.speech.cymru.org/
+  has further information.
+
 nls iso8859-15
 CONFIG_NLS_ISO8859_15
   If you want to display filenames with native language characters
@@ -10091,6 +10163,12 @@
   you compiled aedsp16.o as a module you can specify this parameter as
   'mpu_irq=NN'.
 
+SGI Visual Workstation on-board audio
+CONFIG_SOUND_VWSND
+  Say Y or M if you have an SGI Visual Workstation and you want to
+  be able to use its on-board audio.  Read Documentation/sound/visws
+  for more info on this driver's capabilities.
+
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -10626,11 +10704,23 @@
   If you plan to try to use the kernel on such a machine say Y here.
   Everybody else says N.
 
+Sun 3 support
+CONFIG_SUN3
+  This option enables support for the Sun 3 series of workstations.
+  Be warned that this support is very experimental. You will also
+  want to say Y to 68020 support and N to the other processors below.
+  Currently, it is not possible to build a kernel with support for
+  the Sun 3 and and something else, so make sure you have said N to
+  all the other machines. This option does not support the sun3x series
+  of machines (the Sun 3/80 and 3/460). If you don't want to compile a
+  kernel for a Sun 3, say N.
+
 68020 support
 CONFIG_M68020
   If you anticipate running this kernel on a computer with a MC68020
   processor, say Y. Otherwise, say N. Note that the 68020 requires a
-  68851 MMU (Memory Management Unit) to run Linux/m68k.
+  68851 MMU (Memory Management Unit) to run Linux/m68k, except on the
+  Sun 3, which provides its own version.
 
 68030 support
 CONFIG_M68030
@@ -11082,6 +11172,11 @@
   If you want to use the builtin "LANCE" Ethernet controller on an
   HP300 machine, say Y here.
 
+Sun 3 onboard LANCE support
+CONFIG_SUN3LANCE
+  If you want to use the onboard AMD "LANCE" (le) Ethernet hardware
+  on a Sun 3, you will need to say Y here.
+
 DIO bus support
 CONFIG_DIO
   Say Y here to enable support for the "DIO" expansion bus used in
@@ -11751,31 +11846,6 @@
   will create two modules called ircomm and ircomm_tty. For more
   information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/
 
-IrLPT Protocol
-CONFIG_IRLPT
-  Say Y here if you want to build support for the IrLPT protocol. If
-  you want to compile it as a module, say M here and read
-  Documentation/modules.txt. IrLPT makes it possible to print
-  documents to IrDA capable printers.
-
-IrLPT Client Protocol 
-CONFIG_IRLPT_CLIENT
-  Say Y here if you want to build support for the IrLPT client
-  protocol. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The IrLPT client protocol can be used to
-  print documents to IrDA compatible printers like the HP-5MP, or
-  IrLPT printer adapters like the ACTiSYS IR-100M.
-
-IrLPT Server Protocol 
-CONFIG_IRLPT_SERVER
-  Say Y here if you want to build support for the IrLPT server
-  protocol. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The IrLPT server protocol makes it
-  possible to use a Linux machine as an infrared printer server for
-  other laptops. So if your Linux machine has a cable connection to a
-  printer, then other laptops can use the Linux machine to print out 
-  documents using infrared communication.
-
 IrTTY IrDA Device Driver
 CONFIG_IRTTY_SIR
   Say Y here if you want to build support for the IrTTY line
@@ -11869,6 +11939,15 @@
   normal 9-pin serial port connector, and can currently only be used
   by IrTTY. To activate support for Greenwich dongles you will have to
   insert "irattach -d girbil" in the /etc/irda/drivers script.
+
+Adaptec Airport 1000 and 2000 dongle
+CONFIG_AIRPORT_DONGLE
+  Say Y here if you want to build support for the Adaptec Airport 1000
+  and 2000 dongles. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. The Airport dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY. To activate support for Airport dongles you will have
+  to insert "irattach -d airport" in the /etc/irda/drivers script.
 
 Parallax Litelink dongle
 CONFIG_LITELINK_DONGLE
diff -u --recursive --new-file v2.3.16/linux/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX
--- v2.3.16/linux/Documentation/filesystems/00-INDEX	Sun May  2 09:51:16 1999
+++ linux/Documentation/filesystems/00-INDEX	Sat Sep  4 12:42:30 1999
@@ -22,6 +22,8 @@
 	- info on using filesystems with the SMB protocol (Windows 3.11 and NT)
 sysv-fs.txt
 	- info on the SystemV/Coherent filesystem.
+udf.txt
+	- info and mount options for the UDF filesystem.
 ufs.txt
 	- info on the ufs filesystem.
 umsdos.txt
diff -u --recursive --new-file v2.3.16/linux/Documentation/filesystems/udf.txt linux/Documentation/filesystems/udf.txt
--- v2.3.16/linux/Documentation/filesystems/udf.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/filesystems/udf.txt	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,57 @@
+*
+* ./Documentation/filesystems/udf.txt
+*
+UDF Filesystem version 0.8.9
+
+If you encounter problems with reading UDF discs using this driver,
+please report them to linux_udf@hootie.lvld.hp.com, which is the
+developer's list.
+
+Write support requires a block driver which supports writing. The current
+scsi and ide cdrom drivers do not support writing.
+
+-------------------------------------------------------------------------------
+The following mount options are supported:
+
+	gid=		Set the default group.
+	umask=		Set the default umask.
+	uid=		Set the default user.
+	unhide		Show otherwise hidden files.
+	undelete	Show deleted files in lists.
+	strict		Set strict conformance (unused)
+	utf8		(unused)
+	iocharset	(unused)
+
+The remaining are for debugging and disaster recovery:
+
+	bs=			Set the block size. (may not work unless 2048)
+	novrs		Skip volume sequence recognition 
+
+The following expect a offset from 0.
+
+	session=	Set the CDROM session (default= last session)
+	anchor=		Override standard anchor location. (default= 256)
+	volume=		Override the VolumeDesc location. (unused)
+	partition=	Override the PartitionDesc location. (unused)
+	lastblock=	Set the last block of the filesystem/
+
+The following expect a offset from the partition root.
+
+	fileset=	Override the fileset block location. (unused)
+	rootdir=	Override the root directory location. (unused)
+				WARNING: overriding the rootdir to a non-directory may
+					yield highly unpredictable results.
+-------------------------------------------------------------------------------
+
+
+For more information see:
+	http://www.trylinux.com/projects/udf/index.html
+
+For the latest version and toolset see:
+	 http://www.csc.calpoly.edu/~bfennema/udf.html
+
+Documentation on UDF and ECMA 167 is available FREE from:
+    http://www.osta.org/
+    http://www.ecma.ch/
+
+Ben Fennema <bfennema@falcon.csc.calpoly.edu>
diff -u --recursive --new-file v2.3.16/linux/Documentation/networking/PLIP.txt linux/Documentation/networking/PLIP.txt
--- v2.3.16/linux/Documentation/networking/PLIP.txt	Wed May 20 18:54:34 1998
+++ linux/Documentation/networking/PLIP.txt	Tue Sep  7 10:14:36 1999
@@ -49,17 +49,69 @@
 SLIP).
 
 Performance
-==========
+===========
 
 PLIP easily outperforms Ethernet cards....(ups, I was dreaming, but
 it *is* getting late. EOB)
 
+PLIP driver details
+-------------------
+
+The Linux PLIP driver is an implementation of the original Crynwr protocol,
+that uses the parallel port subsystem of the kernel in order to properly
+share parallel ports between PLIP and other services.
+
+IRQs and trigger timeouts
+=========================
+
+When a parallel port used for a PLIP driver has an IRQ configured to it, the
+PLIP driver is signaled whenever data is sent to it via the cable, such that
+when no data is available, the driver isn't being used.
+
+However, on some machines it is hard, if not impossible, to configure an IRQ
+to a certain parallel port, mainly because it is used by some other device.
+On these machines, the PLIP driver can be used in IRQ-less mode, where
+the PLIP driver would constantly poll the parallel port for data waiting,
+and if such data is available, process it. This mode is less efficient than
+the IRQ mode, because the driver has to check the parallel port many times
+per second, even when no data at all is sent. Some rough measurements
+indicate that there isn't a noticeable performance drop when using IRQ-less
+mode as compared to IRQ mode as far as the data transfer speed is involved.
+There is a performance drop on the machine hosting the driver.
+
+When the PLIP driver is used in IRQ mode, the timeout used for triggering a
+data transfer (the maximal time the PLIP driver would allow the other side
+before announcing a timeout, when trying to handshake a transfer of some
+data) is, by default, 500usec. As IRQ delivery is more or less immediate,
+this timeout is quite sufficient. 
+
+When in IRQ-less mode, the PLIP driver polls the parallel port HZ times
+per second (where HZ is typically 100 on most platforms, and 1024 on an
+Alpha, as of this writing). Between two such polls, there are 10^6/HZ usecs.
+On an i386, for example, 10^6/100 = 10000usec. It is easy to see that it is
+quite possible for the trigger timeout to expire between two such polls, as
+the timeout is only 500usec long. As a result, it is required to change the
+trigger timeout on the *other* side of a PLIP connection, to about
+10^6/HZ usecs. If both sides of a PLIP connection are used in IRQ-less mode,
+this timeout is required on both sides.
+
+It appears that in practice, the trigger timeout can be shorter than in the
+above calculation. It isn't an important issue, unless the wire is faulty,
+in which case a long timeout would stall the machine when, for whatever
+reason, bits are dropped.
+
+A utility that can perform this change in Linux is plipconfig, which is part
+of the net-tools package (its location can be found in the
+Documentation/Changes file). An example command would be
+'plipconfig plipX trigger 10000', where plipX is the appropriate
+PLIP device.
+
 PLIP hardware interconnection
 -----------------------------
 
 PLIP uses several different data transfer methods.  The first (and the
 only one implemented in the early version of the code) uses a standard
-printer "null" cable to transfers data four bits at a time using
+printer "null" cable to transfer data four bits at a time using
 data bit outputs connected to status bit inputs.
 
 The second data transfer method relies on both machines having
@@ -138,18 +190,18 @@
 The PLIP driver is compatible with the "Crynwr" parallel port transfer
 standard in Mode 0.  That standard specifies the following protocol:
 
-   send header nibble '8'
+   send header nibble '0x8'
    count-low octet
    count-high octet
    ... data octets
    checksum octet
 
 Each octet is sent as
-	<wait for rx. '1'>	<send 0x10+(octet&0x0F)>
-	<wait for rx. '0'>	<send 0x00+((octet>>4)&0x0F)>
+	<wait for rx. '0x1?'>	<send 0x10+(octet&0x0F)>
+	<wait for rx. '0x0?'>	<send 0x00+((octet>>4)&0x0F)>
 
 To start a transfer the transmitting machine outputs a nibble 0x08.
-The raises the ACK line, triggering an interrupt in the receiving
+That raises the ACK line, triggering an interrupt in the receiving
 machine.  The receiving machine disables interrupts and raises its own ACK
 line. 
 
diff -u --recursive --new-file v2.3.16/linux/Documentation/networking/irda.txt linux/Documentation/networking/irda.txt
--- v2.3.16/linux/Documentation/networking/irda.txt	Thu Dec 17 09:01:03 1998
+++ linux/Documentation/networking/irda.txt	Tue Sep  7 10:14:36 1999
@@ -1,13 +1,14 @@
 To use the IrDA protocols within Linux you will need to get a suitable copy
 of the IrDA Utilities. More detailed information about these and associated
-programs can be found on http://www.cs.uit.no/~dagb/irda/.
+programs can be found on http://www.cs.uit.no/linux-irda/
 
-For more information about the IrDA protocol stack, see the IR-HOWTO
-written by Werner Heuser <r2d2c3po@zedat.fu-berlin.de>
+For more information about how to use the IrDA protocol stack, see the
+IR-HOWTO (http://www.snafu.de/~wehe/IR-HOWTO.html) written by Werner Heuser
+<wehe@snafu.de>
 
-There is an active mailing list for discussing Linux IrDA matters called
-linux-irda. To subscribe to it, send a message to Majordomo@list.uit.no
-with the words "subscribe linux-irda" in the body of the message, the
-subject field is ignored.
+There is an active mailing list for discussing Linux-IrDA matters called
+linux-irda. To subscribe to it, visit:
+
+	http://www.pasta.cs.uit.no/mailman/listinfo/linux-irda
 
 Dag Brattli <dagb@cs.uit.no>
diff -u --recursive --new-file v2.3.16/linux/MAINTAINERS linux/MAINTAINERS
--- v2.3.16/linux/MAINTAINERS	Tue Aug 31 17:29:12 1999
+++ linux/MAINTAINERS	Tue Sep  7 10:14:36 1999
@@ -104,7 +104,8 @@
 ADVANSYS SCSI DRIVER
 P:	Bob Frey
 M:	Bob Frey <bobf@advansys.com>
-W:	http://www.advansys.com/linux
+W:	http://www.advansys.com/linux.html
+L:	linux-scsi@vger.rutgers.edu
 S:	Maintained
 
 AEDSP16 DRIVER
@@ -441,7 +442,7 @@
 IRDA SUBSYSTEM
 P:      Dag Brattli
 M:      Dag Brattli <dagb@cs.uit.no>
-L:      linux-irda@list.uit.no
+L:      linux-irda@pasta.cs.uit.no
 W:      http://www.cs.uit.no/linux-irda/
 S:      Maintained
 
@@ -808,9 +809,7 @@
 S:	Supported
 
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
-P:	Greg Ungerer
 M:	support@stallion.oz.au
-M:	gerg@stallion.com
 W:	http://www.stallion.com
 S:	Supported
 
@@ -846,6 +845,13 @@
 P:	Dario Ballabio
 M:	dario@milano.europe.dg.com
 L:	linux-scsi@vger.rutgers.edu
+S:	Maintained
+
+UDF FILESYSTEM
+P:	Ben Fennema
+M:	bfennema@falcon.csc.calpoly.edu
+L:	linux_udf@hootie.lvld.hp.com
+W:	http://www.trylinux.com/projects/udf/index.html
 S:	Maintained
 
 UMSDOS FILESYSTEM
diff -u --recursive --new-file v2.3.16/linux/Makefile linux/Makefile
--- v2.3.16/linux/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/Makefile	Fri Sep  3 12:35:08 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 3
-SUBLEVEL = 16
+SUBLEVEL = 17
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -144,6 +144,10 @@
 
 ifdef CONFIG_PCI
 DRIVERS := $(DRIVERS) drivers/pci/pci.a
+endif
+
+ifdef CONFIG_PCMCIA
+DRIVERS := $(DRIVERS) drivers/pcmcia/pcmcia.o
 endif
 
 ifdef CONFIG_DIO
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/Makefile linux/arch/alpha/kernel/Makefile
--- v2.3.16/linux/arch/alpha/kernel/Makefile	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/Makefile	Wed Sep  1 14:37:25 1999
@@ -16,7 +16,7 @@
 
 O_TARGET := kernel.o
 O_OBJS   := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
-	    ptrace.o time.o fpreg.o semaphore.o pci_syscall.o
+	    ptrace.o time.o fpreg.o semaphore.o
 OX_OBJS  := alpha_ksyms.o
 
 
@@ -28,12 +28,11 @@
 	    sys_jensen.o sys_miata.o sys_mikasa.o sys_noritake.o \
 	    sys_rawhide.o sys_ruffian.o sys_sable.o sys_sio.o \
 	    sys_sx164.o sys_takara.o sys_rx164.o \
-	    es1888.o smc37c669.o smc37c93x.o ns87312.o \
-	    pci.o pci_setup.o
+	    es1888.o smc37c669.o smc37c93x.o ns87312.o pci.o
 else
 
 ifdef CONFIG_PCI
-O_OBJS   += pci.o pci_setup.o
+O_OBJS   += pci.o
 endif
 
 # Core logic support
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_apecs.c linux/arch/alpha/kernel/core_apecs.c
--- v2.3.16/linux/arch/alpha/kernel/core_apecs.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_apecs.c	Wed Sep  1 15:34:01 1999
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- v2.3.16/linux/arch/alpha/kernel/core_cia.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_cia.c	Wed Sep  1 15:34:01 1999
@@ -12,7 +12,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_lca.c linux/arch/alpha/kernel/core_lca.c
--- v2.3.16/linux/arch/alpha/kernel/core_lca.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_lca.c	Wed Sep  1 15:34:01 1999
@@ -9,7 +9,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_mcpcia.c linux/arch/alpha/kernel/core_mcpcia.c
--- v2.3.16/linux/arch/alpha/kernel/core_mcpcia.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_mcpcia.c	Wed Sep  1 15:34:01 1999
@@ -6,7 +6,6 @@
  * Code common to all MCbus-PCI Adaptor core logic chipsets
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
--- v2.3.16/linux/arch/alpha/kernel/core_pyxis.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_pyxis.c	Wed Sep  1 15:34:01 1999
@@ -6,7 +6,6 @@
  * Code common to all PYXIS core logic chips.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_t2.c linux/arch/alpha/kernel/core_t2.c
--- v2.3.16/linux/arch/alpha/kernel/core_t2.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_t2.c	Wed Sep  1 15:34:01 1999
@@ -9,7 +9,6 @@
  * Code common to all T2 core logic chips.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/core_tsunami.c linux/arch/alpha/kernel/core_tsunami.c
--- v2.3.16/linux/arch/alpha/kernel/core_tsunami.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/core_tsunami.c	Wed Sep  1 15:34:01 1999
@@ -6,7 +6,6 @@
  * Code common to all TSUNAMI core logic chips.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/pci.h>
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- v2.3.16/linux/arch/alpha/kernel/pci.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/pci.c	Wed Sep  1 15:34:01 1999
@@ -6,7 +6,6 @@
  *	David Mosberger (davidm@cs.arizona.edu)
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -70,19 +69,21 @@
  */
 
 static void __init
-pci_assign_special(void)
+pcibios_assign_special(void)
 {
 	struct pci_dev *dev;
+	int i;
 
-	/* The first three resources of the Cypress IDE controler need
-	   to remain unchanged.  So allocate them as-is.  */
-	dev = NULL;
-	while ((dev = pci_find_device(PCI_VENDOR_ID_CONTAQ,
-				       PCI_DEVICE_ID_CONTAQ_82C693, dev))) {
-		if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-			pci_record_assignment(dev, 0);
-			pci_record_assignment(dev, 1);
-			pci_record_assignment(dev, 2);
+	/* The first three resources of an IDE controler are often magic, 
+	   so leave them unchanged.  This is true, for instance, of the
+	   Contaq 82C693 as seen on SX164 and DP264.  */
+
+	for (dev = pci_devices; dev; dev = dev->next) {
+		if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
+			continue;
+	        for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			if (dev->resource[i].flags)
+				pci_claim_resource(dev, i);
 		}
 	}
 }
@@ -107,40 +108,35 @@
 {
 	/* Propogate hose info into the subordinate devices.  */
 
+	struct pci_controler *hose = probing_hose;
 	struct pci_dev *dev;
-	void *sysdata;
 
-	sysdata = (bus->parent ? bus->parent->sysdata : bus->sysdata);
+	bus->resource[0] = hose->io_space;
+	bus->resource[1] = hose->mem_space;
 	for (dev = bus->devices; dev; dev = dev->sibling)
-		dev->sysdata = sysdata;
+		dev->sysdata = hose;
 }
 
 void __init
-pcibios_base_address_update(struct pci_dev *dev, int resource)
+pcibios_update_resource(struct pci_dev *dev, struct resource *root,
+			struct resource *res, int resource)
 {
-	struct pci_controler *hose = dev->sysdata;
-        struct resource *res = &dev->resource[resource];
-        unsigned long base, where, size;
+        unsigned long where, size;
         u32 reg;
 
-        if (res->flags & IORESOURCE_IO)
-                base = hose->io_space->start;
-        else
-                base = hose->mem_space->start;
-
         where = PCI_BASE_ADDRESS_0 + (resource * 4);
         size = res->end - res->start;
         pci_read_config_dword(dev, where, &reg);
-        reg = (reg & size) | (((u32)(res->start - base)) & ~size);
+        reg = (reg & size) | (((u32)(res->start - root->start)) & ~size);
         pci_write_config_dword(dev, where, reg);
 
 	/* ??? FIXME -- record old value for shutdown.  */
 }
 
 void __init
-pcibios_irq_update(struct pci_dev *dev, u8 irq)
+pcibios_update_irq(struct pci_dev *dev, int irq)
 {
-	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 
 	/* ??? FIXME -- record old value for shutdown.  */
 }
@@ -186,10 +182,10 @@
 	}
 	probing_hose = NULL;
 
-	pci_assign_special();
-	pci_assign_unassigned(alpha_mv.min_io_address,
-			      alpha_mv.min_mem_address);
-	pci_fixup_irq(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
+	pcibios_assign_special();
+	pci_assign_unassigned_resources(alpha_mv.min_io_address,
+				        alpha_mv.min_mem_address);
+	pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
 	pci_set_bus_ranges();
 }
 
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h
--- v2.3.16/linux/arch/alpha/kernel/pci_impl.h	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/pci_impl.h	Wed Sep  1 14:37:25 1999
@@ -127,7 +127,6 @@
 extern struct pci_controler *hose_head, **hose_tail;
 extern struct pci_controler *probing_hose;
 
-/* pci_common.c */
 extern void common_init_pci(void);
 extern u8 common_swizzle(struct pci_dev *, u8 *);
 extern struct pci_controler *alloc_pci_controler(unsigned long *);
@@ -136,11 +135,3 @@
 extern const char *const pci_io_names[];
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
-
-/* pci_setup.c */
-void pci_record_assignment(struct pci_dev *dev, int resource);
-void pci_assign_unassigned(int, int);
-void pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *),
-		   int (*map_irq)(struct pci_dev *, u8, u8));
-void pci_set_bus_ranges(void);
-
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci_setup.c linux/arch/alpha/kernel/pci_setup.c
--- v2.3.16/linux/arch/alpha/kernel/pci_setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/pci_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,328 +0,0 @@
-/*
- *	linux/arch/alpha/kernel/pci_setup.c
- *
- * Extruded from code written by
- *      Dave Rusling (david.rusling@reo.mts.dec.com)
- *      David Mosberger (davidm@cs.arizona.edu)
- *	David Miller (davem@redhat.com)
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/pci.h>
-
-
-#define DEBUG_CONFIG 0
-#if DEBUG_CONFIG
-# define DBGC(args)     printk args
-#else
-# define DBGC(args)
-#endif
-
-
-void __init
-pci_record_assignment(struct pci_dev *dev, int resource)
-{
-	struct pci_controler *hose = dev->sysdata;
-        struct resource *res = &dev->resource[resource];
-	struct resource *base;
-	int ok;
-
-	if (res->flags == 0)
-		return;
-	if (res->flags & IORESOURCE_IO)
-		base = hose->io_space;
-	else
-		base = hose->mem_space;
-
-	res->start += base->start;
-	res->end += base->start;
-
-	ok = request_resource(base, res);
-
-	DBGC(("PCI record assignment: (%s) resource %d %s\n",
-	      dev->name, resource, (ok < 0 ? "failed" : "ok")));
-}
-
-static void inline
-pdev_assign_unassigned(struct pci_dev *dev, int min_io, int min_mem)
-{
-	u32 reg;
-	u16 cmd;
-	int i;
-
-	DBGC(("PCI assign resources : (%s)\n", dev->name));
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		struct pci_controler *hose;
-		struct resource *root, *res;
-		unsigned long size, min, max;
-
-		res = &dev->resource[i];
-
-		if (res->flags & IORESOURCE_IO)
-			cmd |= PCI_COMMAND_IO;
-		else if (res->flags & IORESOURCE_MEM)
-			cmd |= PCI_COMMAND_MEMORY;
-
-		/* If it is already assigned or the resource does
-		   not exist, there is nothing to do.  */
-		if (res->parent != NULL || res->flags == 0UL)
-			continue;
-
-		hose = dev->sysdata;
-
-		/* Determine the root we allocate from.  */
-		if (res->flags & IORESOURCE_IO) {
-			root = hose->io_space;
-			min = root->start + min_io;
-			max = root->end;
-		} else {
-			root = hose->mem_space;
-			min = root->start + min_mem;
-			max = root->end;
-		}
-
-		size = res->end - res->start + 1;
-
-		DBGC(("  for root[%016lx:%016lx]\n"
-		      "       res[%016lx:%016lx]\n"
-		      "      span[%016lx:%016lx] size[%lx]\n",
-		      root->start, root->end, res->start, res->end,
-		      min, max, size));
-
-		if (allocate_resource(root, res, size, min, max, size) < 0) {
-			printk(KERN_ERR
-			       "PCI: Failed to allocate resource %d for %s\n",
-			       i, dev->name);
-		}
-
-		DBGC(("  got res[%016lx:%016lx] for resource %d\n",
-		      res->start, res->end, i));
-
-		/* Update PCI config space.  */
-		pcibios_base_address_update(dev, i);
-	}
-
-	/* Special case, disable the ROM.  Several devices act funny
-	   (ie. do not respond to memory space writes) when it is left
-	   enabled.  A good example are QlogicISP adapters.  */
-
-	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &reg);
-	reg &= ~PCI_ROM_ADDRESS_ENABLE;
-	pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
-
-	/* All of these (may) have I/O scattered all around and may not
-	   use IO-base address registers at all.  So we just have to
-	   always enable IO to these devices.  */
-	if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
-	    || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
-	    || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
-	    || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
-		cmd |= PCI_COMMAND_IO;
-	}
-
-	/* ??? Always turn on bus mastering.  */
-	cmd |= PCI_COMMAND_MASTER;
-
-	/* Enable the appropriate bits in the PCI command register.  */
-	pci_write_config_word(dev, PCI_COMMAND, cmd);
-
-	DBGC(("  cmd reg 0x%x\n", cmd));
-
-	/* If this is a PCI bridge, set the cache line correctly.  */
-	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
-		/* ??? EV4/EV5 cache line is 32 bytes.  */
-		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
-				      (64 / sizeof(u32)));
-	}
-}
-
-void __init
-pci_assign_unassigned(int min_io, int min_mem)
-{
-	struct pci_dev *dev;
-
-	for (dev = pci_devices; dev; dev = dev->next)
-		pdev_assign_unassigned(dev, min_io, min_mem);
-}
-
-struct pbus_set_ranges_data
-{
-	int found_vga;
-	unsigned int io_start, io_end;
-	unsigned int mem_start, mem_end;
-};
-
-static void __init
-pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
-{
-	struct pbus_set_ranges_data inner;
-	struct pci_bus *child;
-	struct pci_dev *dev;
-
-	inner.found_vga = 0;
-	inner.mem_start = inner.io_start = ~0;
-	inner.mem_end = inner.io_end = 0;
-
-	/* Collect information about how our direct children are layed out. */
-	for (dev = bus->devices; dev; dev = dev->sibling) {
-		int i;
-		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-			struct resource *res = &dev->resource[i];
-			if (res->flags & IORESOURCE_IO) {
-				if (res->start < inner.io_start)
-					inner.io_start = res->start;
-				if (res->end > inner.io_end)
-					inner.io_end = res->end;
-			} else if (res->flags & IORESOURCE_MEM) {
-				if (res->start < inner.mem_start)
-					inner.mem_start = res->start;
-				if (res->end > inner.mem_end)
-					inner.mem_end = res->end;
-			}
-		}
-                if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
-                        inner.found_vga = 1;
-	}
-
-	/* And for all of the sub-busses.  */
-	for (child = bus->children; child; child = child->next)
-		pbus_set_ranges(child, &inner);
-
-	/* Align the values.  */
-	inner.io_start &= ~(4*1024 - 1);
-	inner.mem_start &= ~(1*1024*1024 - 1);
-	if (inner.io_end & (4*1024-1))
-		inner.io_end = (inner.io_end | (4*1024 - 1)) + 1;
-	if (inner.mem_end & (1*1024*1024-1))
-		inner.mem_end = (inner.mem_end | (1*1024*1024 - 1)) + 1;
-
-	/* Configure the bridge, if possible.  */
-	if (bus->self) {
-		struct pci_dev *bridge = bus->self;
-		u32 l;
-
-                /* Set up the top and bottom of the PCI I/O segment
-                   for this bus.  */
-                pci_read_config_dword(bridge, PCI_IO_BASE, &l);
-                l &= 0xffff0000;
-                l |= (inner.io_start >> 8) & 0x00f0;
-		l |= (inner.io_end - 1) & 0xf000;
-                pci_write_config_dword(bridge, PCI_IO_BASE, l);
-
-                /*
-                 * Clear out the upper 16 bits of IO base/limit.
-                 * Clear out the upper 32 bits of PREF base/limit.
-                 */
-                pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
-                pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
-                pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
-
-                /* Set up the top and bottom of the PCI Memory segment
-                   for this bus.  */
-                l = (inner.mem_start & 0xfff00000) >> 16;
-		l |= (inner.mem_end - 1) & 0xfff00000;
-                pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
-
-                /*
-                 * Turn off downstream PF memory address range, unless
-                 * there is a VGA behind this bridge, in which case, we
-                 * enable the PREFETCH range to include BIOS ROM at C0000.
-                 *
-                 * NOTE: this is a bit of a hack, done with PREFETCH for
-                 * simplicity, rather than having to add it into the above
-                 * non-PREFETCH range, which could then be bigger than we want.
-                 * We might assume that we could relocate the BIOS ROM, but
-                 * that would depend on having it found by those who need it
-                 * (the DEC BIOS emulator would find it, but I do not know
-                 * about the Xservers). So, we do it this way for now... ;-)
-                 */
-                l = (inner.found_vga) ? 0 : 0x0000ffff;
-                pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
-
-                /*
-                 * Tell bridge that there is an ISA bus in the system,
-                 * and (possibly) a VGA as well.
-                 */
-                l = (inner.found_vga) ? 0x0c : 0x04;
-                pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
-
-                /*
-                 * Clear status bits,
-                 * turn on I/O    enable (for downstream I/O),
-                 * turn on memory enable (for downstream memory),
-                 * turn on master enable (for upstream memory and I/O).
-                 */
-                pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
-	}
-
-	if (outer) {
-		outer->found_vga |= inner.found_vga;
-		if (inner.io_start < outer->io_start)
-			outer->io_start = inner.io_start;
-		if (inner.io_end > outer->io_end)
-			outer->io_end = inner.io_end;
-		if (inner.mem_start < outer->mem_start)
-			outer->mem_start = inner.mem_start;
-		if (inner.mem_end > outer->mem_end)
-			outer->mem_end = inner.mem_end;
-	}
-}
-
-void __init
-pci_set_bus_ranges(void)
-{
-	struct pci_bus *bus;
-
-	for (bus = pci_root; bus; bus = bus->next)
-		pbus_set_ranges(bus, NULL);
-}
-
-static void inline
-pdev_fixup_irq(struct pci_dev *dev,
-	       u8 (*swizzle)(struct pci_dev *, u8 *),
-	       int (*map_irq)(struct pci_dev *, u8, u8))
-{
-	u8 pin, slot;
-	int irq;
-
-	/* If this device is not on the primary bus, we need to figure out
-	   which interrupt pin it will come in on.   We know which slot it
-	   will come in on 'cos that slot is where the bridge is.   Each
-	   time the interrupt line passes through a PCI-PCI bridge we must
-	   apply the swizzle function.  */
-
-	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-	/* Cope with 0 and illegal. */
-	if (pin == 0 || pin > 4)
-		pin = 1;
-
-	/* Follow the chain of bridges, swizzling as we go.  */
-	slot = (*swizzle)(dev, &pin);
-
-	irq = (*map_irq)(dev, slot, pin);
-	if (irq == -1)
-		irq = 0;
-	dev->irq = irq;
-
-	DBGC(("PCI fixup irq : (%s) got %d\n", dev->name, dev->irq));
-
-	/* Always tell the device, so the driver knows what is
-	   the real IRQ to use; the device does not use it. */
-	pcibios_irq_update(dev, irq);
-}
-
-void __init
-pci_fixup_irq(u8 (*swizzle)(struct pci_dev *, u8 *),
-	      int (*map_irq)(struct pci_dev *, u8, u8))
-{
-	struct pci_dev *dev;
-
-	for (dev = pci_devices; dev; dev = dev->next)
-		pdev_fixup_irq(dev, swizzle, map_irq);
-}
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/pci_syscall.c linux/arch/alpha/kernel/pci_syscall.c
--- v2.3.16/linux/arch/alpha/kernel/pci_syscall.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/pci_syscall.c	Wed Dec 31 16:00:00 1969
@@ -1,148 +0,0 @@
-/*
- *	pci_syscall.c
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
-
-
-#ifndef CONFIG_PCI
-
-asmlinkage int sys_pciconfig_read() { return -ENOSYS; }
-asmlinkage int sys_pciconfig_write() { return -ENOSYS; }
-
-#else
-
-asmlinkage long
-sys_pciconfig_read(unsigned long bus, unsigned long dfn,
-		   unsigned long off, unsigned long len, void *buf)
-{
-	struct pci_dev *dev;
-	u8 byte;
-	u16 word;
-	u32 dword;
-	long err, cfg_ret;
-
-	err = -EPERM;
-	if (!capable(CAP_SYS_ADMIN))
-		goto error;
-
-	err = -ENODEV;
-	dev = pci_find_slot(bus, dfn);
-	if (!dev)
-		goto error;
-
-	lock_kernel();
-	switch (len) {
-	case 1:
-		cfg_ret = pci_read_config_byte(dev, off, &byte);
-		break;
-	case 2:
-		cfg_ret = pci_read_config_word(dev, off, &word);
-		break;
-	case 4:
-		cfg_ret = pci_read_config_dword(dev, off, &dword);
-		break;
-	default:
-		err = -EINVAL;
-		unlock_kernel();
-		goto error;
-	};
-	unlock_kernel();
-
-	err = -EIO;
-	if (cfg_ret != PCIBIOS_SUCCESSFUL)
-		goto error;
-
-	switch (len) {
-	case 1:
-		err = put_user(byte, (unsigned char *)buf);
-		break;
-	case 2:
-		err = put_user(word, (unsigned short *)buf);
-		break;
-	case 4:
-		err = put_user(dword, (unsigned int *)buf);
-		break;
-	};
-	return err;
-
-error:
-	/* ??? XFree86 doesn't even check the return value.  They
-	   just look for 0xffffffff in the output, since that's what
-	   they get instead of a machine check on x86.  */
-	switch (len) {
-	case 1:
-		put_user(-1, (unsigned char *)buf);
-		break;
-	case 2:
-		put_user(-1, (unsigned short *)buf);
-		break;
-	case 4:
-		put_user(-1, (unsigned int *)buf);
-		break;
-	};
-	return err;
-}
-
-asmlinkage long
-sys_pciconfig_write(unsigned long bus, unsigned long dfn,
-		    unsigned long off, unsigned long len, void *buf)
-{
-	struct pci_dev *dev;
-	u8 byte;
-	u16 word;
-	u32 dword;
-	int err = 0;
-
-	if (!capable(CAP_SYS_ADMIN))
-		return -EPERM;
-	if (!pcibios_present())
-		return -ENOSYS;
-
-	dev = pci_find_slot(bus, dfn);
-	if (!dev)
-		return -ENODEV;
-
-	lock_kernel();
-	switch(len) {
-	case 1:
-		err = get_user(byte, (u8 *)buf);
-		if (err)
-			break;
-		err = pci_write_config_byte(dev, off, byte);
-		if (err != PCIBIOS_SUCCESSFUL)
-			err = -EIO;
-		break;
-
-	case 2:
-		err = get_user(word, (u16 *)buf);
-		if (err)
-			break;
-		err = pci_write_config_byte(dev, off, word);
-		if (err != PCIBIOS_SUCCESSFUL)
-			err = -EIO;
-		break;
-
-	case 4:
-		err = get_user(dword, (u32 *)buf);
-		if (err)
-			break;
-		pci_write_config_byte(dev, off, dword);
-		if (err != PCIBIOS_SUCCESSFUL)
-			err = -EIO;
-		break;
-
-	default:
-		err = -EINVAL;
-		break;
-	};
-	unlock_kernel();
-
-	return err;
-}
-
-#endif /* CONFIG_PCI */
diff -u --recursive --new-file v2.3.16/linux/arch/alpha/kernel/sys_rawhide.c linux/arch/alpha/kernel/sys_rawhide.c
--- v2.3.16/linux/arch/alpha/kernel/sys_rawhide.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/alpha/kernel/sys_rawhide.c	Wed Sep  1 15:34:01 1999
@@ -24,7 +24,6 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/core_mcpcia.h>
-#include <asm/pci.h>
 
 #include "proto.h"
 #include "irq_impl.h"
diff -u --recursive --new-file v2.3.16/linux/arch/arm/kernel/bios32.c linux/arch/arm/kernel/bios32.c
--- v2.3.16/linux/arch/arm/kernel/bios32.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/kernel/bios32.c	Wed Sep  1 15:34:01 1999
@@ -5,7 +5,6 @@
  *
  * Bits taken from various places.
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.16/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.3.16/linux/arch/arm/mm/proc-sa110.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/arm/mm/proc-sa110.S	Wed Sep  1 15:34:01 1999
@@ -6,7 +6,6 @@
  * These are the low level assembler for performing cache and TLB
  * functions on the sa110.
  */
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/procinfo.h>
diff -u --recursive --new-file v2.3.16/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.3.16/linux/arch/i386/config.in	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/config.in	Fri Sep  3 13:19:52 1999
@@ -5,6 +5,7 @@
 mainmenu_name "Linux Kernel Configuration"
 
 define_bool CONFIG_X86 y
+define_bool CONFIG_ISA y
 
 mainmenu_option next_comment
 comment 'Code maturity level options'
@@ -82,6 +83,8 @@
     define_bool CONFIG_X86_LOCAL_APIC y
   fi
 fi
+
+source drivers/pcmcia/Config.in
 
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
diff -u --recursive --new-file v2.3.16/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.3.16/linux/arch/i386/defconfig	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/defconfig	Tue Sep  7 10:49:32 1999
@@ -2,6 +2,7 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_X86=y
+CONFIG_ISA=y
 
 #
 # Code maturity level options
@@ -50,6 +51,12 @@
 # CONFIG_VISWS is not set
 CONFIG_X86_IO_APIC=y
 CONFIG_X86_LOCAL_APIC=y
+
+#
+# PCMCIA/Cardbus support
+#
+CONFIG_PCMCIA=y
+CONFIG_CARDBUS=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
@@ -358,6 +365,7 @@
 # CONFIG_VFAT_FS is not set
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
+# CONFIG_UDF_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_HPFS_FS is not set
@@ -373,6 +381,8 @@
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c
--- v2.3.16/linux/arch/i386/kernel/apm.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/apm.c	Wed Sep  1 14:19:08 1999
@@ -1391,7 +1391,7 @@
 		}
 	}
 #endif
-	if (((apm_bios_info.flags & APM_BIOS_DISABLED) == 0)
+	if (((apm_bios_info.flags & APM_BIOS_DISENGAGED) == 0)
 	    && (apm_bios_info.version > 0x0100)) {
 		if (apm_engage_power_management(0x0001) == APM_SUCCESS)
 			apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.3.16/linux/arch/i386/kernel/entry.S	Thu Jul 29 15:18:50 1999
+++ linux/arch/i386/kernel/entry.S	Sat Sep  4 13:06:08 1999
@@ -145,7 +145,30 @@
 	andl $-8192,%ebx	# GET_CURRENT
 	movl exec_domain(%ebx),%edx	# Get the execution domain
 	movl 4(%edx),%edx	# Get the lcall7 handler for the domain
+	pushl $0x7
 	call *%edx
+	addl $4, %esp
+	popl %eax
+	jmp ret_from_sys_call
+
+ENTRY(lcall27)
+	pushfl			# We get a different stack layout with call gates,
+	pushl %eax		# which has to be cleaned up later..
+	SAVE_ALL
+	movl EIP(%esp),%eax	# due to call gates, this is eflags, not eip..
+	movl CS(%esp),%edx	# this is eip..
+	movl EFLAGS(%esp),%ecx	# and this is cs..
+	movl %eax,EFLAGS(%esp)	#
+	movl %edx,EIP(%esp)	# Now we move them to their "normal" places
+	movl %ecx,CS(%esp)	#
+	movl %esp,%ebx
+	pushl %ebx
+	andl $-8192,%ebx	# GET_CURRENT
+	movl exec_domain(%ebx),%edx	# Get the execution domain
+	movl 4(%edx),%edx	# Get the lcall7 handler for the domain
+	pushl $0x27
+	call *%edx
+	addl $4, %esp
 	popl %eax
 	jmp ret_from_sys_call
 
diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.3.16/linux/arch/i386/kernel/setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/kernel/setup.c	Sat Sep  4 12:00:42 1999
@@ -266,14 +266,14 @@
        char saved_command_line[COMMAND_LINE_SIZE];
 
 struct resource standard_io_resources[] = {
-	{ "dma1", 0x00, 0x1f },
-	{ "pic1", 0x20, 0x3f },
-	{ "timer", 0x40, 0x5f },
-	{ "keyboard", 0x60, 0x6f },
-	{ "dma page reg", 0x80, 0x8f },
-	{ "pic2", 0xa0, 0xbf },
-	{ "dma2", 0xc0, 0xdf },
-	{ "fpu", 0xf0, 0xff }
+	{ "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
+	{ "pic1", 0x20, 0x3f, IORESOURCE_BUSY },
+	{ "timer", 0x40, 0x5f, IORESOURCE_BUSY },
+	{ "keyboard", 0x60, 0x6f, IORESOURCE_BUSY },
+	{ "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
+	{ "pic2", 0xa0, 0xbf, IORESOURCE_BUSY },
+	{ "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+	{ "fpu", 0xf0, 0xff, IORESOURCE_BUSY }
 };
 
 #define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
@@ -284,7 +284,7 @@
 static struct resource ram_resources[] = {
 	{ "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
 	{ "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
-	{ "Video RAM area", 0x0a0000, 0x0bffff },
+	{ "Video RAM area", 0x0a0000, 0x0bffff, IORESOURCE_BUSY },
 	{ "Kernel code", 0x100000, 0 },
 	{ "Kernel data", 0, 0 }
 };
@@ -293,7 +293,7 @@
 #define MAXROMS 6
 static struct resource rom_resources[MAXROMS] = {
 	{ "System ROM", 0xF0000, 0xFFFFF, IORESOURCE_BUSY },
-	{ "Video ROM", 0xc0000, 0xc7fff }
+	{ "Video ROM", 0xc0000, 0xc7fff, IORESOURCE_BUSY }
 };
 
 #define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
@@ -337,6 +337,7 @@
 				rom_resources[roms].start = base;
 				rom_resources[roms].end = base + length - 1;
 				rom_resources[roms].name = "Extension ROM";
+				rom_resources[roms].flags = IORESOURCE_BUSY;
 
 				request_resource(&iomem_resource, rom_resources + roms);
 				roms++;
@@ -354,6 +355,7 @@
 		rom_resources[roms].start = base;
 		rom_resources[roms].end = base + 65535;
 		rom_resources[roms].name = "Extension ROM";
+		rom_resources[roms].flags = IORESOURCE_BUSY;
 
 		request_resource(&iomem_resource, rom_resources + roms);
 	}
diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.3.16/linux/arch/i386/kernel/smp.c	Wed Aug 18 11:34:50 1999
+++ linux/arch/i386/kernel/smp.c	Tue Sep  7 10:03:07 1999
@@ -731,7 +731,11 @@
 
  	value = apic_read(APIC_SPIV);
  	value |= (1<<8);		/* Enable APIC (bit==1) */
+#if 0
  	value &= ~(1<<9);		/* Enable focus processor (bit==0) */
+#else
+	value |= (1<<9);		/* Disable focus processor (bit==1) */
+#endif
 	value |= 0xff;			/* Set spurious IRQ vector to 0xff */
  	apic_write(APIC_SPIV,value);
 
diff -u --recursive --new-file v2.3.16/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.3.16/linux/arch/i386/kernel/traps.c	Wed Aug 18 11:27:34 1999
+++ linux/arch/i386/kernel/traps.c	Sat Sep  4 13:06:08 1999
@@ -46,8 +46,10 @@
 
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
+asmlinkage void lcall27(void);
 
-struct desc_struct default_ldt = { 0, 0 };
+struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
+		{ 0, 0 }, { 0, 0 } };
 
 /*
  * The IDT has to be page-aligned to simplify the Pentium
@@ -67,8 +69,8 @@
 { \
 	tsk->thread.error_code = error_code; \
 	tsk->thread.trap_no = trapnr; \
-	force_sig(signr, tsk); \
 	die_if_no_fixup(str,regs,error_code); \
+	force_sig(signr, tsk); \
 }
 
 #define DO_VM86_ERROR(trapnr, signr, str, name, tsk) \
@@ -696,9 +698,11 @@
 	set_system_gate(SYSCALL_VECTOR,&system_call);
 
 	/*
-	 * default LDT is a single-entry callgate to lcall7
+	 * default LDT is a single-entry callgate to lcall7 for iBCS
+	 * and a callgate to lcall27 for Solaris/x86 binaries
 	 */
-	set_call_gate(&default_ldt,lcall7);
+	set_call_gate(&default_ldt[0],lcall7);
+	set_call_gate(&default_ldt[4],lcall27);
 
 	/*
 	 * on SMP we do not yet know which CPU is on which TSS,
diff -u --recursive --new-file v2.3.16/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.3.16/linux/arch/i386/mm/init.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/i386/mm/init.c	Tue Sep  7 10:38:21 1999
@@ -375,7 +375,6 @@
 	int datapages = 0;
 	int initpages = 0;
 	unsigned long tmp;
-	unsigned long addr;
 	int i, avail;
 
 	end_mem &= PAGE_MASK;
@@ -413,17 +412,27 @@
 	/* walk the whitelist, unreserving good memory
 	 */
 	for (avail = i = 0; i < e820.nr_map; i++) {
+		unsigned long addr, end, size;
+
 		if (e820.map[i].type != 1)	/* not usable memory */
 			continue;
-		printk("memory region: %luk @ %08lx\n",
-				    ((long)(e820.map[i].size)) / 1024,
-				    (long)(e820.map[i].addr) );
-		for (addr=PAGE_ALIGN(((long)(e820.map[i].addr)))+PAGE_OFFSET,
-								     tmp = 0;
-				     tmp < (unsigned long)(e820.map[i].size);
-							    tmp += PAGE_SIZE,
-							   addr += PAGE_SIZE) {
+		addr = e820.map[i].addr;
+		size = e820.map[i].size;
+
+		/* Overflow large memory reasonably gracefully */
+		if (addr != e820.map[i].addr)
+			continue;
+
+		printk("memory region: %luk @ %08lx\n", size >> 10, addr );
+
+		/* Make sure we don't get fractional pages */
+		end = (addr + size) & PAGE_MASK;
+		addr = PAGE_ALIGN(addr);
+		if (end <= addr)
+			continue;
 
+		size = end - addr;
+		for (addr = addr + PAGE_OFFSET ; size ; addr += PAGE_SIZE, size -= PAGE_SIZE) {
 			/* this little bit of grossness is for dealing
 			 * with memory borrowing for system bookkeeping
 			 * (smp stacks, zero page, kernel code, etc)
@@ -437,9 +446,11 @@
 			 * in any case, we don't want to hack mem_map
 			 * entries above end_mem.
 			 */
-			if ( (addr < start_low_mem)
-			  || (addr >= HIGH_MEMORY && addr <= start_mem)
-			  || (addr > end_mem) )
+			if ( addr < start_low_mem )
+				continue;
+			if ( addr > end_mem )
+				continue;
+			if ( addr >= HIGH_MEMORY && addr <= start_mem )
 				continue;
 
 			avail++;
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/Makefile linux/arch/m68k/Makefile
--- v2.3.16/linux/arch/m68k/Makefile	Sun Aug 15 11:47:29 1999
+++ linux/arch/m68k/Makefile	Sat Sep  4 13:06:41 1999
@@ -24,7 +24,11 @@
 	CROSS_COMPILE = m68k-linux-
 endif
 
+ifndef CONFIG_SUN3
 LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux.lds
+else
+LINKFLAGS = -T $(TOPDIR)/arch/m68k/vmlinux-sun3.lds -N
+endif
 
 # without -fno-strength-reduce the 53c7xx.c driver fails ;-(
 CFLAGS += -pipe -fno-strength-reduce -ffixed-a2
@@ -50,7 +54,11 @@
 CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g
 endif
 
+ifndef CONFIG_SUN3
 HEAD := arch/m68k/kernel/head.o
+else
+HEAD := arch/m68k/kernel/sun3-head.o
+endif 
 
 SUBDIRS += arch/m68k/kernel arch/m68k/mm arch/m68k/lib
 CORE_FILES := arch/m68k/kernel/kernel.o arch/m68k/mm/mm.o $(CORE_FILES)
@@ -106,6 +114,11 @@
 SUBDIRS := $(SUBDIRS) arch/m68k/sun3x
 endif
 
+ifdef CONFIG_SUN3
+CORE_FILES := $(CORE_FILES) arch/m68k/sun3/sun3.o arch/m68k/sun3/prom/promlib.a
+SUBDIRS := $(SUBDIRS) arch/m68k/sun3 arch/m68k/sun3/prom
+endif
+
 ifdef CONFIG_M68040
 CORE_FILES := $(CORE_FILES) arch/m68k/fpsp040/fpsp.o
 SUBDIRS := $(SUBDIRS) arch/m68k/fpsp040
@@ -132,7 +145,7 @@
 
 vmlinux.gz: vmlinux
 
-ifdef CONFIG_KGDB
+ifndef CONFIG_KGDB
 	cp vmlinux vmlinux.tmp
 	$(STRIP) vmlinux.tmp
 	gzip -9c vmlinux.tmp >vmlinux.gz
@@ -141,8 +154,21 @@
 	gzip -9c vmlinux >vmlinux.gz
 endif
 
+bzImage: vmlinux.bz2
+
+vmlinux.bz2: vmlinux
+
+ifndef CONFIG_KGDB
+	cp vmlinux vmlinux.tmp
+	$(STRIP) vmlinux.tmp
+	bzip2 -1c vmlinux.tmp >vmlinux.bz2
+	rm vmlinux.tmp
+else
+	bzip2 -1c vmlinux >vmlinux.bz2
+endif
+
 archclean:
-	rm -f vmlinux.gz
+	rm -f vmlinux.gz vmlinux.bz2
 	rm -f arch/m68k/kernel/m68k_defs.h arch/m68k/kernel/m68k_defs.d
 
 archmrproper:
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/amiga/amiints.c linux/arch/m68k/amiga/amiints.c
--- v2.3.16/linux/arch/m68k/amiga/amiints.c	Sun Aug 15 11:47:29 1999
+++ linux/arch/m68k/amiga/amiints.c	Sat Sep  4 13:06:41 1999
@@ -117,7 +117,7 @@
 	cia_init_IRQ(&ciab_base);
 }
 
-static inline void amiga_insert_irq(irq_node_t **list, irq_node_t *node)
+static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node)
 {
 	unsigned long flags;
 	irq_node_t *cur;
@@ -133,7 +133,7 @@
 
 	if (node->flags & SA_INTERRUPT) {
 		if (node->flags & SA_SHIRQ)
-			return;
+			return -EBUSY;
 		/*
 		 * There should never be more than one
 		 */
@@ -152,6 +152,7 @@
 	*list = node;
 
 	restore_flags(flags);
+	return 0;
 }
 
 static inline void amiga_delete_irq(irq_node_t **list, void *dev_id)
@@ -186,6 +187,7 @@
                       unsigned long flags, const char *devname, void *dev_id)
 {
 	irq_node_t *node;
+	int error = 0;
 
 	if (irq >= AMI_IRQS) {
 		printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__,
@@ -218,7 +220,7 @@
 		node->dev_id  = dev_id;
 		node->devname = devname;
 		node->next    = NULL;
-		amiga_insert_irq(&ami_irq_list[irq], node);
+		error = amiga_insert_irq(&ami_irq_list[irq], node);
 	} else {
 		ami_irq_list[irq]->handler = handler;
 		ami_irq_list[irq]->flags   = flags;
@@ -230,7 +232,7 @@
 	if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq])
 		custom.intena = IF_SETCLR | ami_intena_vals[irq];
 
-	return 0;
+	return error;
 }
 
 void amiga_free_irq(unsigned int irq, void *dev_id)
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/atari/stdma.c linux/arch/m68k/atari/stdma.c
--- v2.3.16/linux/arch/m68k/atari/stdma.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/atari/stdma.c	Sat Sep  4 13:06:41 1999
@@ -29,6 +29,7 @@
 
 
 #include <linux/types.h>
+#include <linux/kdev_t.h>
 #include <linux/genhd.h>
 #include <linux/sched.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.3.16/linux/arch/m68k/config.in	Thu Aug 26 13:05:34 1999
+++ linux/arch/m68k/config.in	Sat Sep  4 13:06:41 1999
@@ -198,8 +198,8 @@
   fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
-  bool 'MAC NCR5380 SCSI' CONFIG_MAC_SCSI
-  dep_tristate 'MAC NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI
+  bool 'Macintosh NCR5380 SCSI' CONFIG_MAC_SCSI
+  dep_tristate 'Macintosh NCR53c9[46] SCSI' CONFIG_SCSI_MAC_ESP $CONFIG_SCSI
 fi
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
 
@@ -329,19 +329,19 @@
 if [ "$CONFIG_AMIGA" = "y" ]; then
   tristate 'Amiga mouse support' CONFIG_AMIGAMOUSE
   if [ "$CONFIG_AMIGAMOUSE" != "n" ]; then
-    define_bool CONFIG_MOUSE y
+    define_bool CONFIG_BUSMOUSE y
   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari mouse support' CONFIG_ATARIMOUSE
   if [ "$CONFIG_ATARIMOUSE" != "n" ]; then
-    define_bool CONFIG_MOUSE y
+    define_bool CONFIG_BUSMOUSE y
   fi
 fi
 if [ "$CONFIG_MAC" = "y" ]; then
    bool 'Mac ADB mouse support' CONFIG_ADBMOUSE
   if [ "$CONFIG_ADBMOUSE" != "n" ]; then
-    define_bool CONFIG_MOUSE y
+    define_bool CONFIG_BUSMOUSE y
   fi
 fi
 if [ "$CONFIG_ATARI" = "y" ]; then
@@ -381,7 +381,7 @@
     bool 'Sun keyboard support' CONFIG_SUN_KEYBOARD
     bool 'Sun mouse support' CONFIG_SUN_MOUSE
     if [ "$CONFIG_SUN_MOUSE" != "n" ]; then
-      define_bool CONFIG_MOUSE y
+      define_bool CONFIG_BUSMOUSE y
     fi
     define_bool CONFIG_SBUS y
     define_bool CONFIG_SBUSCHAR y
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- v2.3.16/linux/arch/m68k/kernel/Makefile	Thu Dec 17 09:06:29 1998
+++ linux/arch/m68k/kernel/Makefile	Sat Sep  4 13:06:41 1999
@@ -10,11 +10,16 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 
+ifndef CONFIG_SUN3
 all: head.o kernel.o
+else
+all: sun3-head.o kernel.o
+endif 
+
 O_TARGET := kernel.o
 O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
-	  setup.o sys_m68k.o time.o
-OX_OBJS := m68k_ksyms.o
+	  sys_m68k.o time.o semaphore.o
+OX_OBJS := setup.o m68k_ksyms.o
 
 ifdef CONFIG_KGDB
 O_OBJS += kgdb.o
@@ -25,6 +30,8 @@
 endif
 
 head.o: head.S m68k_defs.h
+
+sun3-head.o: sun3-head.S m68k_defs.h
 
 m68k_defs.h: m68k_defs.c m68k_defs.head
 	rm -f m68k_defs.d
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.3.16/linux/arch/m68k/kernel/entry.S	Sun Aug 15 11:47:29 1999
+++ linux/arch/m68k/kernel/entry.S	Sat Sep  4 13:06:41 1999
@@ -72,6 +72,16 @@
 	pea	SYMBOL_NAME(ret_from_exception)
 	jmp	SYMBOL_NAME(schedule)
 
+	| After a fork we jump here directly from resume,
+	| so that %d1 contains the previous task
+	| Theoretically only needed on SMP, but let's watch
+	| what happens in schedule_tail() in future...
+ENTRY(ret_from_fork)
+	movel	%d1,%sp@-
+	jsr	SYMBOL_NAME(schedule_tail)
+	addql	#4,%sp
+	jra	SYMBOL_NAME(ret_from_exception)
+
 badsys:
 	movel	#-ENOSYS,PT_D0(%sp)
 	jra	SYMBOL_NAME(ret_from_exception)
@@ -88,16 +98,6 @@
 	subql	#4,%sp			| dummy return address
 	SAVE_SWITCH_STACK
 	jbsr	SYMBOL_NAME(syscall_trace)
-
-	| After a fork we jump here directly from resume,
-	| so that %d1 contains the previous task
-	| Theoretically only needed on SMP, but let's watch
-	| what happens in schedule_tail() in future...
-ENTRY(ret_from_fork)
-	movel	%d1,%sp@-
-	jsr	SYMBOL_NAME(schedule_tail)
-	addql	#4,%sp
-	jra	SYMBOL_NAME(ret_from_exception)
 
 SYMBOL_NAME_LABEL(ret_from_signal)
 	RESTORE_SWITCH_STACK
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/kgdb.c linux/arch/m68k/kernel/kgdb.c
--- v2.3.16/linux/arch/m68k/kernel/kgdb.c	Thu Jul 30 11:08:19 1998
+++ linux/arch/m68k/kernel/kgdb.c	Sat Sep  4 13:06:41 1999
@@ -189,6 +189,11 @@
 #include <asm/amigahw.h>
 #include <asm/amigaints.h>
 #endif
+#ifdef CONFIG_MAC
+#include <linux/tty.h>
+#include <asm/bootinfo.h>
+#include <asm/macints.h>
+#endif
 
 
 #undef DEBUG
@@ -239,6 +244,15 @@
 extern int amiga_ser_out( unsigned char c );
 extern unsigned char amiga_ser_in( void );
 #endif
+#ifdef CONFIG_MAC
+static unsigned char mac_scca_in( void );
+static unsigned char mac_scca_out( unsigned char c );
+static unsigned char mac_scca_intr( void ); 
+static unsigned char mac_sccb_in( void );
+static unsigned char mac_sccb_out( unsigned char c);
+static unsigned char mac_sccb_intr( void );
+extern void mac_init_scc_port( int cflag, int port );
+#endif
 
 /************************* End of Prototypes **************************/
 
@@ -668,6 +682,31 @@
 	}
 #endif
 
+#ifdef CONFIG_MAC
+	if (MACH_IS_MAC) {
+		if (!strcmp( m68k_debug_device, "ser" ) ||
+		    !strcmp( m68k_debug_device, "ser1" )) {
+			mac_init_scc_port( B9600|CS8, 0 );
+			serial_in = mac_scca_in;
+			serial_out = mac_scca_out;
+			serial_intr = mac_scca_intr;
+		} else if (!strcmp( m68k_debug_device, "ser2" )) {
+			mac_init_scc_port( B9600|CS8, 1 );
+			serial_in = mac_sccb_in;
+			serial_out = mac_sccb_out;
+			serial_intr = mac_sccb_intr;
+		}
+	}
+	if (!serial_in || !serial_out) {
+		if (*m68k_debug_device)
+			printk( "kgdb_init failed: no valid serial device!\n" );
+		else
+			printk( "kgdb not enabled\n" );
+		return;
+	}
+	request_irq(4, kgdb_intr, IRQ_TYPE_FAST, "kgdb", NULL);
+#endif
+
 #ifdef CONFIG_ATARI
 	if (!serial_in || !serial_out) {
 		if (*m68k_debug_device)
@@ -781,8 +820,15 @@
   /* copy format/vector word */
   "		movew	%a0@("FRAMEOFF_VECTOR"),%a1@("GDBOFF_VECTOR")\n"
   /* save FPU regs */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+  "		tstl	"SYMBOL_NAME_STR(m68k_fputype)"\n"
+  "		jeq	1f\n"
+#endif
   "		fmovemx	%fp0-%fp7,%a1@("GDBOFF_FP0")\n"
   "		fmoveml	%fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
+  "1:\n"
+#endif	/* CONFIG_M68KFPU_EMU_ONLY */
 
   /* set stack to CPU frame */
   "		addl	#"FRAMEOFF_SR",%a0\n"
@@ -801,8 +847,15 @@
 
   /* after return, first restore FPU registers */
   "		movel	#"SYMBOL_NAME_STR(kgdb_registers)",%a0\n" /* source */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+  "		tstl	"SYMBOL_NAME_STR(m68k_fputype)"\n"
+  "		jeq	1f\n"
+#endif
   "		fmovemx	%a0@("GDBOFF_FP0"),%fp0-%fp7\n"
   "		fmoveml	%a0@("GDBOFF_FPCTL"),%fpcr/%fpsr/%fpiar\n"
+  "1:\n"
+#endif	/* CONFIG_M68KFPU_EMU_ONLY */
   /* set new stack pointer */
   "		movel	%a0@("GDBOFF_A7"),%sp\n"
   "		clrw	%sp@-\n"		/* fake format $0 frame */
@@ -849,8 +902,15 @@
   /* fake format 0 and vector 1 (translated to SIGINT) */
   "		movew	#4,%a1@("GDBOFF_VECTOR")\n"
   /* save FPU regs */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
+#ifdef CONFIG_M68KFPU_EMU
+  "		tstl	"SYMBOL_NAME_STR(m68k_fputype)"\n"
+  "		jeq	1f\n"
+#endif
   "		fmovemx	%fp0-%fp7,%a1@("GDBOFF_FP0")\n"
   "		fmoveml	%fpcr/%fpsr/%fpiar,%a1@("GDBOFF_FPCTL")\n"
+  "1:\n"
+#endif	/* CONFIG_M68KFPU_EMU_ONLY */
   /* pop off the CPU stack frame */
   "		addql	#8,%sp\n"
   "		movel	%sp,%a1@("GDBOFF_A7")\n" /* save a7 now */
@@ -1188,6 +1248,114 @@
 	}
 	scc.cha_b_ctrl = 0x38; /* reset highest IUS */
 	MFPDELAY();
+	return( c );
+}
+
+#endif
+
+/* -------------------- Macintosh serial I/O -------------------- */
+
+#ifdef CONFIG_MAC
+
+struct SCC
+ {
+  u_char cha_b_ctrl;
+  u_char char_dummy1;
+  u_char cha_a_ctrl;
+  u_char char_dummy2;
+  u_char cha_b_data;
+  u_char char_dummy3;
+  u_char cha_a_data;
+ };
+
+#define scc (*((volatile struct SCC*)mac_bi_data.sccbase))
+
+#define uSEC 1
+#define LONG_DELAY()				\
+    do {					\
+	int i;					\
+	for( i = 60*uSEC; i > 0; --i )		\
+	    barrier();				\
+    } while(0)
+
+static unsigned char mac_sccb_out (unsigned char c)
+{
+    int i;
+    do {
+	LONG_DELAY();
+    } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+    for( i = uSEC; i > 0; --i )
+	barrier();
+    scc.cha_b_data = c;
+}
+
+static unsigned char mac_scca_out (unsigned char c)
+{
+    int i;
+    do {
+	LONG_DELAY();
+    } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+    for( i = uSEC; i > 0; --i )
+	barrier();
+    scc.cha_a_data = c;
+}
+
+static unsigned char mac_sccb_in( void )
+{
+    do {
+	LONG_DELAY();
+    } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
+    LONG_DELAY();
+    return( scc.cha_b_data );
+}
+
+static unsigned char mac_scca_in( void )
+
+{
+    do {
+	LONG_DELAY();
+    } while( !(scc.cha_a_ctrl & 0x01) ); /* wait for rx buf filled */
+    LONG_DELAY();
+    return( scc.cha_a_data );
+}
+
+static unsigned char mac_sccb_intr( void )
+
+{	unsigned char c, stat;
+	
+	LONG_DELAY();
+	scc.cha_b_ctrl = 1; /* RR1 */
+	LONG_DELAY();
+	stat = scc.cha_b_ctrl;
+	LONG_DELAY();
+	c = scc.cha_b_data;
+	LONG_DELAY();
+	if (stat & 0x30) {
+		scc.cha_b_ctrl = 0x30; /* error reset for overrun and parity */
+		LONG_DELAY();
+	}
+	scc.cha_b_ctrl = 0x38; /* reset highest IUS */
+	LONG_DELAY();
+	return( c );
+}
+
+static unsigned char mac_scca_intr( void )
+
+{	unsigned char c, stat;
+	
+	LONG_DELAY();
+	scc.cha_a_ctrl = 1; /* RR1 */
+	LONG_DELAY();
+	stat = scc.cha_a_ctrl;
+	LONG_DELAY();
+	c = scc.cha_a_data;
+	LONG_DELAY();
+	if (stat & 0x30) {
+		scc.cha_a_ctrl = 0x30; /* error reset for overrun and parity */
+		LONG_DELAY();
+	}
+	scc.cha_a_ctrl = 0x38; /* reset highest IUS */
+	LONG_DELAY();
 	return( c );
 }
 
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c
--- v2.3.16/linux/arch/m68k/kernel/m68k_ksyms.c	Mon Aug  9 12:27:30 1999
+++ linux/arch/m68k/kernel/m68k_ksyms.c	Sat Sep  4 13:06:41 1999
@@ -38,11 +38,14 @@
 EXPORT_SYMBOL(mm_ptov);
 EXPORT_SYMBOL(mm_end_of_chunk);
 #endif
-EXPORT_SYMBOL(mm_vtop_fallback);
 EXPORT_SYMBOL(m68k_realnum_memory);
 EXPORT_SYMBOL(m68k_memory);
+#ifndef CONFIG_SUN3
+EXPORT_SYMBOL(mm_vtop_fallback);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(kernel_set_cachemode);
+#endif
 EXPORT_SYMBOL(m68k_debug_device);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_thread);
@@ -53,7 +56,6 @@
 EXPORT_SYMBOL(local_bh_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(kernel_set_cachemode);
 EXPORT_SYMBOL(kernel_thread);
 
 /* Networking helper routines. */
@@ -67,6 +69,7 @@
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memcmp);
+EXPORT_SYMBOL_NOVERS(memscan);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
 EXPORT_SYMBOL_NOVERS(__down_failed_interruptible);
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.3.16/linux/arch/m68k/kernel/process.c	Sun Aug 15 11:47:29 1999
+++ linux/arch/m68k/kernel/process.c	Sat Sep  4 13:06:41 1999
@@ -45,7 +45,7 @@
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 union task_union init_task_union
-__attribute__((section("init_task"), aligned(THREAD_SIZE)))
+__attribute__((section("init_task"), aligned(KTHREAD_SIZE)))
 	= { task: INIT_TASK(init_task_union.task) };
 
 asmlinkage void ret_from_fork(void);
@@ -90,10 +90,14 @@
 {
 	if (mach_reset)
 		mach_reset();
+	for (;;);
 }
 
 void machine_halt(void)
 {
+	if (mach_halt)
+		mach_halt();
+	for (;;);
 }
 
 void machine_power_off(void)
@@ -101,6 +105,10 @@
 #if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
 	apm_set_power_state(APM_STATE_OFF);
 #endif
+
+	if (mach_power_off)
+		mach_power_off();
+	for (;;);
 }
 
 void show_regs(struct pt_regs * regs)
@@ -138,7 +146,7 @@
 	   "trap #0\n\t"		/* Linux/m68k system call */
 	   "tstl %0\n\t"		/* child or parent */
 	   "jne 1f\n\t"			/* parent - jump */
-	   "lea %%sp@(-8192),%6\n\t"	/* reload current */
+	   "lea %%sp@(%c7),%6\n\t"	/* reload current */
 	   "movel %3,%%sp@-\n\t"	/* push argument */
 	   "jsr %4@\n\t"		/* call fn */
 	   "movel %0,%%d1\n\t"		/* pass exit value */
@@ -147,7 +155,8 @@
 	   "1:"
 	   : "=d" (retval)
 	   : "0" (__NR_clone), "i" (__NR_exit),
-	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current)
+	     "r" (arg), "a" (fn), "d" (clone_arg), "r" (current),
+	     "i" (-KTHREAD_SIZE)
 	   : "d0", "d2");
 	pid = retval;
 	}
@@ -204,7 +213,7 @@
 	struct switch_stack * childstack, *stack;
 	unsigned long stack_offset, *retp;
 
-	stack_offset = THREAD_SIZE - sizeof(struct pt_regs);
+	stack_offset = KTHREAD_SIZE - sizeof(struct pt_regs);
 	childregs = (struct pt_regs *) ((unsigned long) p + stack_offset);
 
 	*childregs = *regs;
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/semaphore.c linux/arch/m68k/kernel/semaphore.c
--- v2.3.16/linux/arch/m68k/kernel/semaphore.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/kernel/semaphore.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,129 @@
+/*
+ *  Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/sched.h>
+#include <asm/semaphore-helper.h>
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * Notably, the inline "up()" and "down()" functions can
+ * efficiently test if they need to do any extra work (up
+ * needs to do something only if count was negative before
+ * the increment operation.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit.  ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore.  The others will go back
+ * to sleep.
+ *
+ * Note that these functions are only called when there is
+ * contention on the lock, and as such all this is the
+ * "non-critical" part of the whole semaphore business. The
+ * critical part is the inline stuff in <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+void __up(struct semaphore *sem)
+{
+	wake_one_more(sem);
+	wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function.  Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible.  This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return.  If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR				\
+	struct task_struct *tsk = current;	\
+	wait_queue_t wait;			\
+	init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state)						\
+									\
+									\
+	tsk->state = (task_state);					\
+	add_wait_queue(&sem->wait, &wait);				\
+									\
+	/*								\
+	 * Ok, we're set up.  sem->count is known to be less than zero	\
+	 * so we must wait.						\
+	 *								\
+	 * We can let go the lock for purposes of waiting.		\
+	 * We re-acquire it after awaking so as to protect		\
+	 * all semaphore operations.					\
+	 *								\
+	 * If "up()" is called before we call waking_non_zero() then	\
+	 * we will catch it right away.  If it is called later then	\
+	 * we will have to go through a wakeup cycle to catch it.	\
+	 *								\
+	 * Multiple waiters contend for the semaphore lock to see	\
+	 * who gets to gate through and who has to wait some more.	\
+	 */								\
+	for (;;) {
+
+#define DOWN_TAIL(task_state)			\
+		tsk->state = (task_state);	\
+	}					\
+	tsk->state = TASK_RUNNING;		\
+	remove_wait_queue(&sem->wait, &wait);
+
+void __down(struct semaphore * sem)
+{
+	DOWN_VAR
+	DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+	if (waking_non_zero(sem))
+		break;
+	schedule();
+	DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __down_interruptible(struct semaphore * sem)
+{
+	int ret = 0;
+	DOWN_VAR
+	DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+	ret = waking_non_zero_interruptible(sem, tsk);
+	if (ret)
+	{
+		if (ret == 1)
+			/* ret != 0 only if we get interrupted -arca */
+			ret = 0;
+		break;
+	}
+	schedule();
+	DOWN_TAIL(TASK_INTERRUPTIBLE)
+	return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+	return waking_non_zero_trylock(sem);
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.3.16/linux/arch/m68k/kernel/setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/kernel/setup.c	Sat Sep  4 13:06:41 1999
@@ -19,6 +19,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 #include <asm/bootinfo.h>
 #include <asm/setup.h>
@@ -76,6 +77,8 @@
 int (*mach_hwclk) (int, struct hwclk_time*) = NULL;
 int (*mach_set_clock_mmss) (unsigned long) = NULL;
 void (*mach_reset)( void );
+void (*mach_halt)( void ) = NULL;
+void (*mach_power_off)( void ) = NULL;
 long mach_max_dma_address = 0x00ffffff; /* default set to the lower 16MB */
 #if defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY) || defined(CONFIG_BLK_DEV_FD)
 void (*mach_floppy_setup) (char *, int *) __initdata = NULL;
@@ -100,6 +103,9 @@
 #ifdef CONFIG_HEARTBEAT
 void (*mach_heartbeat) (int) = NULL;
 #endif
+#ifdef CONFIG_M68K_L2_CACHE
+void (*mach_l2_flush) (int) = NULL;
+#endif
 
 extern void base_trap_init(void);
 
@@ -118,7 +124,7 @@
 extern void config_amiga(void);
 extern void config_atari(void);
 extern void config_mac(void);
-extern void config_sun3(void);
+extern void config_sun3(unsigned long *, unsigned long *);
 extern void config_apollo(void);
 extern void config_mvme147(void);
 extern void config_mvme16x(void);
@@ -127,8 +133,10 @@
 extern void config_q40(void);
 extern void config_sun3x(void);
 
-#define MASK_256K 0xfffc0000
+extern void mac_debugging_short (int, short);
+extern void mac_debugging_long  (int, long);
 
+#define MASK_256K 0xfffc0000
 
 static void __init m68k_parse_bootinfo(const struct bi_record *record)
 {
@@ -205,13 +213,22 @@
 	else if (CPU_IS_060)
 		m68k_is040or060 = 6;
 
+#ifndef CONFIG_SUN3
 	base_trap_init();
+#endif
 
+	/* FIXME: m68k_fputype is passed in by Penguin booter, which can
+	 * be confused by software FPU emulation. BEWARE.
+	 * We should really do our own FPU check at startup.
+	 * [what do we do with buggy 68LC040s? if we have problems
+	 *  with them, we should add a test to check_bugs() below] */
+#ifndef CONFIG_M68KFPU_EMU_ONLY
 	/* clear the fpu if we have one */
 	if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
 		volatile int zero = 0;
 		asm __volatile__ ("frestore %0" : : "m" (zero));
 	}
+#endif	
 
 	init_mm.start_code = PAGE_OFFSET;
 	init_mm.end_code = (unsigned long) &_etext;
@@ -272,7 +289,7 @@
 #endif
 #ifdef CONFIG_SUN3
 	    case MACH_SUN3:
-	    	config_sun3();
+	    	config_sun3(memory_start_p, memory_end_p);
 	    	break;
 #endif
 #ifdef CONFIG_APOLLO
@@ -321,10 +338,12 @@
 	}
 #endif
 
+#ifndef CONFIG_SUN3
 	*memory_start_p = availmem;
 	*memory_end_p = 0;
 	for (i = 0; i < m68k_num_memory; i++)
 		*memory_end_p += m68k_memory[i].size & MASK_256K;
+#endif
 }
 
 int get_cpuinfo(char * buffer)
@@ -354,6 +373,9 @@
 	clockfactor = 0;
     }
 
+#ifdef CONFIG_M68KFPU_EMU_ONLY
+    fpu="none(soft float)";
+#else
     if (m68k_fputype & FPU_68881)
 	fpu = "68881";
     else if (m68k_fputype & FPU_68882)
@@ -366,6 +388,7 @@
 	fpu = "Sun FPA";
     else
 	fpu = "none";
+#endif
 
     if (m68k_mmutype & MMU_68851)
 	mmu = "68851";
@@ -452,6 +475,9 @@
   m68k_unregister_serial(i);
 #endif
 }
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+
 #ifdef CONFIG_SERIAL_CONSOLE
 long serial_console_init(long kmem_start, long kmem_end)
 {
@@ -461,6 +487,8 @@
 #endif
 #if defined(M68K_SERIAL) && defined(CONFIG_SERIAL_CONSOLE)
   return m68k_serial_console_init(kmem_start, kmem_end);
+#else
+  return kmem_start;
 #endif
 }
 #endif
@@ -496,7 +524,7 @@
 
 void check_bugs(void)
 {
-#ifndef CONFIG_FPU_EMU
+#ifndef CONFIG_M68KFPU_EMU
 	if (m68k_fputype == 0) {
 		printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
 				"WHICH IS REQUIRED BY LINUX/M68K ***\n" );
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/sun3-head.S linux/arch/m68k/kernel/sun3-head.S
--- v2.3.16/linux/arch/m68k/kernel/sun3-head.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/kernel/sun3-head.S	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,102 @@
+#include <linux/config.h>
+#include <linux/linkage.h>
+
+#include <asm/page.h>
+#include <asm/contregs.h>
+#include <asm/sun3-head.h>
+
+PSL_HIGHIPL     = 0x2700
+NBSG            = 0x20000
+ICACHE_ONLY	= 0x00000009
+CACHES_OFF	= 0x00000008	| actually a clear and disable --m
+#define MAS_STACK INT_STACK 
+ROOT_TABLE_SIZE = 128
+PAGESIZE	= 8192
+
+.globl SYMBOL_NAME(bootup_user_stack)
+.globl SYMBOL_NAME(bootup_kernel_stack)
+.globl SYMBOL_NAME(pg0)
+.globl SYMBOL_NAME(empty_bad_page)
+.globl SYMBOL_NAME(empty_bad_page_table)
+.globl SYMBOL_NAME(empty_zero_page)
+.globl SYMBOL_NAME(swapper_pg_dir)
+.globl SYMBOL_NAME(kernel_pmd_table)
+.global SYMBOL_NAME(m68k_pgtable_cachemode)
+.global SYMBOL_NAME(kpt)
+| todo: all these should be in bss!
+SYMBOL_NAME(swapper_pg_dir):                .skip 0x2000
+SYMBOL_NAME(pg0):                           .skip 0x2000
+SYMBOL_NAME(empty_bad_page):                .skip 0x2000
+SYMBOL_NAME(empty_bad_page_table):          .skip 0x2000
+SYMBOL_NAME(kernel_pmd_table):              .skip 0x2000
+SYMBOL_NAME(empty_zero_page):               .skip 0x2000
+
+.globl SYMBOL_NAME(kernel_pg_dir)
+.equ    SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table)
+
+	.section .head
+ENTRY(_stext)
+ENTRY(_start)
+
+/* Firstly, disable interrupts and set up function codes. */
+	movew	#PSL_HIGHIPL, %sr
+	moveq	#FC_CONTROL, %d0	
+	movec	%d0, %sfc	
+	movec	%d0, %dfc	
+
+/* Make sure we're in context zero. */
+	moveq	#0, %d0
+	movsb	%d0, AC_CONTEXT
+
+/* Copy mappings for first megabyte of RAM to address 0xE000000. */
+	lea	(AC_SEGMAP+0),%a0		
+	lea	(AC_SEGMAP+KERNBASE),%a1	
+	moveq	#(0x140000/NBSG-1),%d0
+1:	movsb	%a0@,%d1			
+	movsb	%d1,%a1@
+	addl	#NBSG,%a0		
+	addl	#NBSG,%a1
+	dbf	%d0,1b
+	
+/* Disable caches and jump to high code. */
+	moveq	#ICACHE_ONLY,%d0	| Cache disabled until we're ready to enable it
+	movc	%d0, %cacr	|   is this the right value? (yes --m)
+	jmp	1f:l		
+
+/* Following code executes at high addresses (0xE000xxx). */
+1:	lea	SYMBOL_NAME(init_task_union),%a2	| get initial thread...
+	lea	%a2@(KTHREAD_SIZE),%sp			| ...and its stack.
+
+/* copy bootinfo records from the loader to _end */
+	lea	SYMBOL_NAME(_end), %a1
+	lea	BI_START, %a0
+	/* number of longs to copy */
+	movel	%a0@, %d0
+1:	addl	#4, %a0
+	movel   %a0@, %a1@
+	addl	#4, %a1
+	dbf	%d0, 1b
+	
+/* Point MSP at an invalid page to trap if it's used. --m */
+	movl	#(PAGESIZE),%d0
+	movc	%d0,%msp
+	moveq	#-1,%d0
+	movsb	%d0,(AC_SEGMAP+0x0)
+
+	jbsr	SYMBOL_NAME(sun3_init)
+		
+        jbsr    SYMBOL_NAME(start_kernel)
+	trap	#15			
+
+        .data
+        .even
+SYMBOL_NAME_LABEL(kpt)
+        .long 0
+SYMBOL_NAME_LABEL(availmem)
+        .long 0
+| todo: remove next two. --m
+SYMBOL_NAME_LABEL(is_medusa)
+        .long 0
+SYMBOL_NAME_LABEL(m68k_pgtable_cachemode)
+        .long 0
+
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.3.16/linux/arch/m68k/kernel/traps.c	Sun Aug 15 11:47:29 1999
+++ linux/arch/m68k/kernel/traps.c	Sat Sep  4 13:06:41 1999
@@ -47,7 +47,9 @@
 asmlinkage void trap(void);
 asmlinkage void inthandler(void);
 asmlinkage void nmihandler(void);
+#ifdef CONFIG_M68KFPU_EMU
 asmlinkage void fpu_emu(void);
+#endif
 
 e_vector vectors[256] = {
 	0, 0, buserr, trap, trap, trap, trap, trap,
@@ -68,8 +70,17 @@
 
 void __init base_trap_init(void)
 {
+#ifdef CONFIG_SUN3
+	/* Keep the keyboard interrupt working with PROM for debugging. --m */
+	e_vector *old_vbr;
+	__asm__ volatile ("movec %%vbr,%1\n\t"
+			  "movec %0,%%vbr"
+			  : "=&r" (old_vbr) : "r" ((void*)vectors));
+	vectors[0x1E] = old_vbr[0x1E];	/* Copy int6 vector. */
+#else
 	/* setup the exception vector table */
 	__asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+#endif
 
 	if (CPU_IS_040 && !FPU_IS_EMU) {
 		/* set up FPSP entry points */
@@ -143,6 +154,10 @@
 	if (MACH_IS_AMIGA) {
 		vectors[VEC_INT7] = nmihandler;
 	}
+#ifdef CONFIG_SUN3
+	/* Moved from setup_arch() */
+	base_trap_init();
+#endif
 }
 
 
@@ -175,11 +190,17 @@
 	"MMU CONFIGURATION ERROR"
 	};
 
+#ifndef CONFIG_SUN3
 static char *space_names[] = {
 	"Space 0", "User Data", "User Program", "Space 3",
 	"Space 4", "Super Data", "Super Program", "CPU"
 	};
-
+#else
+static char *space_names[] = {
+	"Space 0", "User Data", "User Program", "Control",
+	"Space 4", "Super Data", "Super Program", "CPU"
+	};
+#endif
 
 void die_if_kernel(char *,struct pt_regs *,int);
 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
@@ -330,6 +351,17 @@
 #endif
 		errorcode = ((mmusr & MMU_R_040) ? 1 : 0) |
 			((ssw & RW_040) ? 0 : 2);
+#ifdef CONFIG_FTRACE
+		{
+			unsigned long flags;
+
+			save_flags(flags);
+			cli();
+			do_ftrace(0xfa000000 | errorcode);
+			do_ftrace(mmusr);
+			restore_flags(flags);
+		}
+#endif
 		do_page_fault (&fp->ptregs, addr, errorcode);
 	} else {
 		printk ("68040 access error, ssw=%x\n", ssw);
@@ -363,6 +395,132 @@
 }
 #endif /* CONFIG_M68040 */
 
+#if defined(CONFIG_SUN3)
+#include <asm/sun3mmu.h>
+
+extern int mmu_emu_handle_fault (unsigned long, int, int);
+
+/* sun3 version of bus_error030 */
+
+extern inline void bus_error030 (struct frame *fp)
+{
+	unsigned char buserr_type = sun3_get_buserr ();
+	unsigned long addr, errorcode;
+	unsigned short ssw = fp->un.fmtb.ssw;
+
+#if DEBUG
+	if (ssw & (FC | FB))
+		printk ("Instruction fault at %#010lx\n",
+			ssw & FC ?
+			fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2
+			:
+			fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr);
+	if (ssw & DF) 
+		printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+			ssw & RW ? "read" : "write",
+			fp->un.fmtb.daddr,
+			space_names[ssw & DFC], fp->ptregs.pc);
+#endif
+
+	/*
+	 * Check if this page should be demand-mapped. This needs to go before
+	 * the testing for a bad kernel-space access (demand-mapping applies
+	 * to kernel accesses too).
+	 */
+	
+	if ((ssw & DF)
+	    && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) {
+		if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0))
+			return;
+	}
+
+	/* Check for kernel-space pagefault (BAD). */
+	if (fp->ptregs.sr & PS_S) {
+		/* kernel fault must be a data fault to user space */
+		if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) {
+		     // try checking the kernel mappings before surrender
+		     if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1))
+			  return;
+			/* instruction fault or kernel data fault! */
+			if (ssw & (FC | FB))
+				printk ("Instruction fault at %#010lx\n",
+					fp->ptregs.pc);
+			if (ssw & DF) {
+				printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
+					ssw & RW ? "read" : "write",
+					fp->un.fmtb.daddr,
+					space_names[ssw & DFC], fp->ptregs.pc);
+			}
+			printk ("BAD KERNEL BUSERR\n");
+
+			die_if_kernel("Oops", &fp->ptregs,0);
+			force_sig(SIGKILL, current);
+			return;
+		}
+	} else {
+		/* user fault */
+		if (!(ssw & (FC | FB)) && !(ssw & DF))
+			/* not an instruction fault or data fault! BAD */
+			panic ("USER BUSERR w/o instruction or data fault");
+	}
+
+
+	/* First handle the data fault, if any.  */
+	if (ssw & DF) {
+		addr = fp->un.fmtb.daddr;
+
+// errorcode bit 0:	0 -> no page		1 -> protection fault
+// errorcode bit 1:	0 -> read fault		1 -> write fault
+
+// (buserr_type & SUN3_BUSERR_PROTERR)	-> protection fault
+// (buserr_type & SUN3_BUSERR_INVALID)	-> invalid page fault
+
+		if (buserr_type & SUN3_BUSERR_PROTERR)
+			errorcode = 0x01;
+		else if (buserr_type & SUN3_BUSERR_INVALID)
+			errorcode = 0x00;
+		else {
+			printk ("*** unexpected busfault type=%#04x\n", buserr_type);
+			printk ("invalid %s access at %#lx from pc %#lx\n",
+				!(ssw & RW) ? "write" : "read", addr,
+				fp->ptregs.pc);
+			die_if_kernel ("Oops", &fp->ptregs, buserr_type);
+			force_sig (SIGSEGV, current);
+			return;
+		}
+
+//todo: wtf is RM bit? --m
+		if (!(ssw & RW) || ssw & RM)
+			errorcode |= 0x02;
+
+		/* Handle page fault. */
+		do_page_fault (&fp->ptregs, addr, errorcode);
+
+		/* Retry the data fault now. */
+		return;
+	}
+
+	/* Now handle the instruction fault. */
+
+	/* Get the fault address. */
+	if (fp->ptregs.format == 0xA)
+		addr = fp->ptregs.pc + 4;
+	else
+		addr = fp->un.fmtb.baddr;
+	if (ssw & FC)
+		addr -= 2;
+
+	if (buserr_type & SUN3_BUSERR_INVALID) {
+		if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0))
+			do_page_fault (&fp->ptregs, addr, 0);
+       } else {
+#ifdef DEBUG
+		printk ("protection fault on insn access (segv).\n");
+#endif
+		force_sig (SIGSEGV, current);
+       }	
+}
+#else
 #if defined(CPU_M68020_OR_M68030)
 static inline void bus_error030 (struct frame *fp)
 {
@@ -568,6 +726,7 @@
 		      : "a" (addr));
 }
 #endif /* CPU_M68020_OR_M68030 */
+#endif /* !CONFIG_SUN3 */
 
 asmlinkage void buserr_c(struct frame *fp)
 {
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/Makefile linux/arch/m68k/mac/Makefile
--- v2.3.16/linux/arch/m68k/mac/Makefile	Sat Jun 13 13:14:32 1998
+++ linux/arch/m68k/mac/Makefile	Sat Sep  4 13:06:41 1999
@@ -7,11 +7,9 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-EXTRA_CFLAGS := -Wa,-m68020
-
 O_TARGET := mac.o
-O_OBJS	 := config.o bootparse.o macints.o via6522.o \
-		mackeyb.o adb-bus.o macboing.o debug.o
 OX_OBJS  := mac_ksyms.o
+O_OBJS	 := config.o bootparse.o macints.o iop.o via.o oss.o psc.o \
+		macboing.o debug.o misc.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/bootparse.c linux/arch/m68k/mac/bootparse.c
--- v2.3.16/linux/arch/m68k/mac/bootparse.c	Thu Feb 12 16:30:13 1998
+++ linux/arch/m68k/mac/bootparse.c	Sat Sep  4 13:06:41 1999
@@ -1,6 +1,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <asm/irq.h>
 #include <asm/setup.h>
 #include <asm/bootinfo.h>
 #include <asm/macintosh.h>
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/config.c linux/arch/m68k/mac/config.c
--- v2.3.16/linux/arch/m68k/mac/config.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/mac/config.c	Sat Sep  4 13:06:41 1999
@@ -37,7 +37,20 @@
 #include <asm/macints.h>
 #include <asm/machw.h>
 
-#include "via6522.h"
+#include <asm/mac_iop.h>
+#include <asm/mac_via.h>
+#include <asm/mac_oss.h>
+#include <asm/mac_psc.h>
+
+/* Offset between Unix time (1970-based) and Mac time (1904-based) */
+
+#define MAC_TIME_OFFSET 2082844800
+
+/*
+ * hardware reset vector
+ */
+
+static void (*rom_reset)(void);
 
 /* Mac bootinfo struct */
 
@@ -59,30 +72,21 @@
 unsigned long mac_orig_videoaddr;
 
 /* Mac specific keyboard functions */
-extern int mac_keyb_init(void);
-extern int mac_kbdrate(struct kbd_repeat *k);
-extern void mac_kbd_leds(unsigned int leds);
-
-/* Mac specific irq functions */
-extern void mac_init_IRQ (void);
-extern void (*mac_handlers[]) (int, void *, struct pt_regs *);
-extern int mac_request_irq (unsigned int irq,
-			    void (*handler)(int, void *, struct pt_regs *),
-                            unsigned long flags, const char *devname,
-			    void *dev_id);
-extern void mac_free_irq (unsigned int irq, void *dev_id);
-extern void mac_enable_irq (unsigned int);
-extern void mac_disable_irq (unsigned int);
-static void mac_get_model(char *model);
-/*static int mac_get_hardware_list(char *buffer);*/
-extern int mac_get_irq_list (char *);
+extern int mackbd_init_hw(void);
+extern void mackbd_leds(unsigned int leds);
 
 /* Mac specific timer functions */
 extern unsigned long mac_gettimeoffset (void);
 static void mac_gettod (int *, int *, int *, int *, int *, int *);
 static int mac_hwclk (int, struct hwclk_time *);
 static int mac_set_clock_mmss (unsigned long);
+extern void iop_preinit(void);
+extern void iop_init(void);
+extern void via_init(void);
 extern void via_init_clock(void (*func)(int, void *, struct pt_regs *));
+extern void via_flush_cache(void);
+extern void oss_init(void);
+extern void psc_init(void);
 
 extern void (*kd_mksound)(unsigned int, unsigned int);
 extern void mac_mksound(unsigned int, unsigned int);
@@ -95,6 +99,18 @@
 extern void mac_debug_init(void);
 extern void mac_debugging_long(int, long);
 
+/* poweroff functions */
+extern void via_poweroff(void);
+extern void oss_poweroff(void);
+extern void adb_poweroff(void);
+extern void adb_hwreset(void);
+
+/* pram functions */
+extern __u32 via_read_time(void);
+extern void via_write_time(__u32);
+extern __u32 adb_read_time(void);
+extern void adb_write_time(__u32);
+
 #ifdef CONFIG_MAGIC_SYSRQ
 static char mac_sysrq_xlate[128] =
 	"\000sdfghzxcv\000bqwer"				/* 0x00 - 0x0f */
@@ -124,104 +140,195 @@
 
 extern int console_loglevel;
 
-/*
- * This function translates the boot timeval into a proper date, to initialize
- * the system time.
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
  */
+static unsigned long mktime(unsigned int year, unsigned int mon,
+	unsigned int day, unsigned int hour,
+	unsigned int min, unsigned int sec)
+{
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+	    (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+	      year*365 - 719499
+	    )*24 + hour /* now have hours */
+	   )*60 + min /* now have minutes */
+	  )*60 + sec; /* finally seconds */
+}
 
-static void mac_gettod (int *yearp, int *monp, int *dayp,
-		 int *hourp, int *minp, int *secp)
+/*
+ * This function translates seconds since 1970 into a proper date.
+ *
+ * Algorithm cribbed from glibc2.1, __offtime().
+ */
+#define SECS_PER_MINUTE (60)
+#define SECS_PER_HOUR  (SECS_PER_MINUTE * 60)
+#define SECS_PER_DAY   (SECS_PER_HOUR * 24)
+
+static void unmktime(unsigned long time, long offset,
+		     int *yearp, int *monp, int *dayp,
+		     int *hourp, int *minp, int *secp)
 {
-	unsigned long time;
-	int leap, oldleap, isleap;
-	int mon_days[14] = { -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1 };
-
-	time = mac_bi_data.boottime - 60*mac_bi_data.gmtbias; /* seconds */
-
-	*minp = time / 60;
-	*secp = time - (*minp * 60);
-	time  = *minp;				/* minutes now */
-
-	*hourp = time / 60;
-	*minp  = time - (*hourp * 60);
-	time   = *hourp;			/* hours now */
-
-	*dayp  = time / 24;
-	*hourp = time - (*dayp * 24);
-	time   = *dayp;				/* days now ... */
-
-	/* for leap day calculation */
-	*yearp = (time / 365) + 1970;		/* approx. year */
-
-	/* leap year calculation - there's an easier way, I bet. And it's broken :-( */
-	/* calculate leap days up to previous year */
-	oldleap =  (*yearp-1)/4 - (*yearp-1)/100 + (*yearp-1)/400;
-	/* calculate leap days incl. this year */
-	leap    =  *yearp/4 - *yearp/100 + *yearp/400;
-	/* this year a leap year ?? */
-	isleap  = (leap != oldleap);
-
-	/* adjust days: days, excluding past leap days since epoch */
-	time  -= oldleap - (1970/4 - 1970/100 + 1970/400);
-
-	/* precise year, and day in year */
-	*yearp = (time / 365);			/* #years since epoch */
-	*dayp  = time - (*yearp * 365) + 1;	/* #days this year (0: Jan 1) */
-	*yearp += 70;				/* add epoch :-) */
-	time = *dayp;
-	
-	if (isleap)				/* add leap day ?? */
-		mon_days[2] += 1;
-
-	/* count the months */
-	for (*monp = 1; time > mon_days[*monp]; (*monp)++) 
-		time -= mon_days[*monp];
+        /* How many days come before each month (0-12).  */
+	static const unsigned short int __mon_yday[2][13] =
+	{
+		/* Normal years.  */
+		{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+		/* Leap years.  */
+		{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+	};
+	long int days, rem, y, wday, yday;
+	const unsigned short int *ip;
+
+	days = time / SECS_PER_DAY;
+	rem = time % SECS_PER_DAY;
+	rem += offset;
+	while (rem < 0) {
+		rem += SECS_PER_DAY;
+		--days;
+	}
+	while (rem >= SECS_PER_DAY) {
+		rem -= SECS_PER_DAY;
+		++days;
+	}
+	*hourp = rem / SECS_PER_HOUR;
+	rem %= SECS_PER_HOUR;
+	*minp = rem / SECS_PER_MINUTE;
+	*secp = rem % SECS_PER_MINUTE;
+	/* January 1, 1970 was a Thursday. */
+	wday = (4 + days) % 7; /* Day in the week. Not currently used */
+	if (wday < 0) wday += 7;
+	y = 1970;
+
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+#define __isleap(year)	\
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
 
-	*dayp = time;
+	while (days < 0 || days >= (__isleap (y) ? 366 : 365))
+	{
+		/* Guess a corrected year, assuming 365 days per year.  */
+		long int yg = y + days / 365 - (days % 365 < 0);
 
+		/* Adjust DAYS and Y to match the guessed year.  */
+		days -= ((yg - y) * 365
+			 + LEAPS_THRU_END_OF (yg - 1)
+			 - LEAPS_THRU_END_OF (y - 1));
+		y = yg;
+	}
+	*yearp = y - 1900;
+	yday = days; /* day in the year.  Not currently used. */
+	ip = __mon_yday[__isleap(y)];
+	for (y = 11; days < (long int) ip[y]; --y)
+		continue;
+	days -= ip[y];
+	*monp = y;
+	*dayp = days + 1; /* day in the month */
 	return;
 }
 
+/*
+ * Return the boot time for use in initializing the kernel clock.
+ *
+ * I'd like to read the hardware clock here but many machines read
+ * the PRAM through ADB, and interrupts aren't initialized when this
+ * is called so ADB obviously won't work.
+ */
+
+static void mac_gettod(int *yearp, int *monp, int *dayp,
+		       int *hourp, int *minp, int *secp)
+{
+	/* Yes the GMT bias is backwards.  It looks like Penguin is
+           screwing up the boottime it gives us... This works for me
+           in Canada/Eastern but it might be wrong everywhere else. */
+	unmktime(mac_bi_data.boottime, -mac_bi_data.gmtbias * 60,
+		yearp, monp, dayp, hourp, minp, secp);
+	/* For some reason this is off by one */
+	*monp = *monp + 1;
+}
+
 /* 
- * TBI: read and write hwclock
+ * Read/write the hardware clock.
  */
 
-static int mac_hwclk( int op, struct hwclk_time *t )
+static int mac_hwclk(int op, struct hwclk_time *t)
 {
-    return 0;
+	unsigned long now;
+
+	if (!op) { /* read */
+		if (macintosh_config->adb_type == MAC_ADB_II) {
+			now = via_read_time();
+		} else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
+			   (macintosh_config->adb_type == MAC_ADB_CUDA)) {
+			now = adb_read_time();
+		} else if (macintosh_config->adb_type == MAC_ADB_IOP) {
+			now = via_read_time();
+		} else {
+			now = MAC_TIME_OFFSET;
+		}
+
+		now -= MAC_TIME_OFFSET;
+
+		t->wday = 0;
+		unmktime(now, 0,
+			 &t->year, &t->mon, &t->day,
+			 &t->hour, &t->min, &t->sec);
+	} else { /* write */
+		now = mktime(t->year + 1900, t->mon + 1, t->day,
+			     t->hour, t->min, t->sec) + MAC_TIME_OFFSET;
+
+		if (macintosh_config->adb_type == MAC_ADB_II) {
+			via_write_time(now);
+		} else if ((macintosh_config->adb_type == MAC_ADB_IISI) ||
+			   (macintosh_config->adb_type == MAC_ADB_CUDA)) {
+			adb_write_time(now);
+		} else if (macintosh_config->adb_type == MAC_ADB_IOP) {
+			via_write_time(now);
+		}
+	}
+	return 0;
 }
 
 /*
- * TBI: set minutes/seconds in hwclock
+ * Set minutes/seconds in the hardware clock
  */
 
 static int mac_set_clock_mmss (unsigned long nowtime)
 {
-    short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+	struct hwclk_time now;
+
+	mac_hwclk(0, &now);
+	now.sec = nowtime % 60;
+	now.min = (nowtime / 60) % 60;
+	mac_hwclk(1, &now);
 
-    return 0;
+	return 0;
 }
 
+#if 0
 void mac_waitbut (void)
 {
 	;
 }
+#endif
 
 extern struct consw fb_con;
 extern struct fb_info *mac_fb_init(long *);
-extern void mac_video_setup(char *, int *);
-
-void (*mac_handlers[8])(int, void *, struct pt_regs *)=
-{
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler,
-	mac_default_handler
-};
 
     /*
      *  Parse a Macintosh-specific record in the bootinfo
@@ -237,7 +344,7 @@
 	    mac_bi_data.id = *data;
 	    break;
 	case BI_MAC_VADDR:
-	    mac_bi_data.videoaddr = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+	    mac_bi_data.videoaddr = *data;
 	    break;
 	case BI_MAC_VDEPTH:
 	    mac_bi_data.videodepth = *data;
@@ -249,7 +356,8 @@
 	    mac_bi_data.dimensions = *data;
 	    break;
 	case BI_MAC_VLOGICAL:
-	    mac_bi_data.videological = *data;
+	    mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+	    mac_orig_videoaddr = *data;
 	    break;
 	case BI_MAC_SCCBASE:
 	    mac_bi_data.sccbase = *data;
@@ -266,6 +374,9 @@
 	case BI_MAC_CPUID:
 	    mac_bi_data.cpuid = *data;
 	    break;
+        case BI_MAC_ROMBASE:
+	    mac_bi_data.rombase = *data;
+	    break;
 	default:
 	    unknown = 1;
     }
@@ -280,12 +391,11 @@
 
 static void mac_cache_card_flush(int writeback)
 {
-	unsigned long flags;
-	save_flags(flags);
+	unsigned long cpu_flags;
+	save_flags(cpu_flags);
 	cli();
-	via_write(via2, vBufB, via_read(via2,vBufB)&~VIA2B_vMode32);
-	via_write(via2, vBufB, via_read(via2,vBufB)|VIA2B_vMode32);
-	restore_flags(flags);
+	via_flush_cache();
+	restore_flags(cpu_flags);
 }
 
 void __init config_mac(void)
@@ -295,22 +405,15 @@
       printk("ERROR: no Mac, but config_mac() called!! \n");
     }
     
-    mac_debug_init();
-        
     mach_sched_init      = mac_sched_init;
-    mach_keyb_init       = mac_keyb_init;
-    mach_kbdrate         = mac_kbdrate;
-    mach_kbd_leds        = mac_kbd_leds;
+    mach_keyb_init       = mackbd_init_hw;
+    mach_kbd_leds        = mackbd_leds;
     mach_init_IRQ        = mac_init_IRQ;
     mach_request_irq     = mac_request_irq;
     mach_free_irq        = mac_free_irq;
     enable_irq           = mac_enable_irq;
     disable_irq          = mac_disable_irq;
-#if 1
-    mach_default_handler = &mac_handlers;
-#endif
     mach_get_model	 = mac_get_model;
-    mach_get_irq_list	 = mac_get_irq_list;
     mach_gettimeoffset   = mac_gettimeoffset;
     mach_gettod          = mac_gettod;
     mach_hwclk           = mac_hwclk;
@@ -319,11 +422,12 @@
     mach_mksound         = mac_mksound;
 #endif
     mach_reset           = mac_reset;
+    mach_halt            = mac_poweroff;
+    mach_power_off       = mac_poweroff;
     conswitchp	         = &dummy_con;
     mach_max_dma_address = 0xffffffff;
 #if 0
     mach_debug_init	 = mac_debug_init;
-    mach_video_setup	 = mac_video_setup;
 #endif
     kd_mksound		 = mac_mksound;
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -346,18 +450,15 @@
     mac_identify();
     mac_report_hardware();
     
-    if(
-    	/* Cache cards */
-        macintosh_config->ident == MAC_MODEL_IICI||
-    	macintosh_config->ident == MAC_MODEL_IISI||
-    	macintosh_config->ident == MAC_MODEL_IICX||
-    	/* On board L2 cache */
-    	macintosh_config->ident == MAC_MODEL_IIFX)
-    {
+    /* AFAIK only the IIci takes a cache card.  The IIfx has onboard
+       cache ... someone needs to figure out how to tell if it's on or
+       not. */
+    if (macintosh_config->ident == MAC_MODEL_IICI
+	|| macintosh_config->ident == MAC_MODEL_IIFX) {
     	mach_l2_flush = mac_cache_card_flush;
     }
-    /* goes on forever if timers broken */
 #ifdef MAC_DEBUG_SOUND
+    /* goes on forever if timers broken */
     mac_mksound(1000,10);
 #endif
 
@@ -365,7 +466,9 @@
      * Check for machine specific fixups.
      */
 
+#ifdef OLD_NUBUS_CODE
     nubus_sweep_video();
+#endif
 }	
 
 
@@ -386,6 +489,13 @@
 static struct mac_model mac_data_table[]=
 {
 	/*
+	 *	The default machine, in case we get an unsupported one
+	 *	We'll pretend to be a Macintosh II, that's pretty safe.
+	 */
+
+	{	MAC_MODEL_II,	"Unknown",	MAC_ADB_II,	MAC_VIA_II,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+
+	/*
 	 *	Original MacII hardware
 	 *	
 	 */
@@ -403,10 +513,11 @@
 	 *	The IIfx apparently has different ADB hardware, and stuff
 	 *	so zany nobody knows how to drive it.
 	 *	Even so, with Marten's help we'll try to deal with it :-)
+	 * CSA: see http://developer.apple.com/technotes/hw/hw_09.html
 	 */
 
 	{	MAC_MODEL_IICI,	"IIci",	MAC_ADB_II,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_IIFX,	"IIfx",	MAC_ADB_II,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_IIFX,	"IIfx",	MAC_ADB_IOP,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_IOP,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_IISI, "IIsi",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_IIVI,	"IIvi",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
 	{	MAC_MODEL_IIVX,	"IIvx",	MAC_ADB_IISI,	MAC_VIA_IIci,	MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
@@ -435,70 +546,72 @@
 	 *	confuse us. The 840AV has a SCSI location of its own (same as
 	 *	the 660AV).
 	 */	 
-
+	 
 	{	MAC_MODEL_Q605, "Quadra 605", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,		MAC_NUBUS},
 	{	MAC_MODEL_Q610, "Quadra 610", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q630, "Quadra 630", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_QUADRA, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
  	{	MAC_MODEL_Q650, "Quadra 650", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	/*	The Q700 does have a NS Sonic */
-	{	MAC_MODEL_Q700, "Quadra 700",   MAC_ADB_II,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q700, "Quadra 700", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_QUADRA2,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q800, "Quadra 800", MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE,   MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
 	{	MAC_MODEL_Q840, "Quadra 840AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_MACE,		MAC_NUBUS},
-	/* These might have IOP problems */
-	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
-	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IISI, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q900, "Quadra 900", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_Q950, "Quadra 950", MAC_ADB_IOP, MAC_VIA_QUADRA, MAC_SCSI_QUADRA2, MAC_IDE_NONE,   MAC_SCC_IOP,	MAC_ETHER_SONIC,	MAC_NUBUS},
 
 	/* 
 	 *	Performa - more LC type machines
 	 */
 
-	{	MAC_MODEL_P460,  "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P475,  "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
-	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
-	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,	MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,	MAC_IDE_NONE,	MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-#if 0	/* other sources seem to suggest the P630/Q630/LC630 is more like LCIII */
-	{	MAC_MODEL_P630,  "Performa 630", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
-#endif
+	{	MAC_MODEL_P460,  "Performa 460", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD, 	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P475,  "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
+	{	MAC_MODEL_P475F, "Performa 475", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
+	{	MAC_MODEL_P520,  "Performa 520", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+
+	{	MAC_MODEL_P550,  "Performa 550", MAC_ADB_CUDA, MAC_VIA_IIci,   MAC_SCSI_OLD,    MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P575,  "Performa 575", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE, MAC_NUBUS},
+	/* These have the comm slot, and therefore the possibility of SONIC ethernet */
+	{	MAC_MODEL_P588,  "Performa 588", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_QUADRA, MAC_SCC_II,	MAC_ETHER_SONIC, MAC_NUBUS},
+	{	MAC_MODEL_TV,    "TV",           MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_P600,  "Performa 600", MAC_ADB_IISI, MAC_VIA_IIci,   MAC_SCSI_OLD,	MAC_IDE_NONE,   MAC_SCC_II,	MAC_ETHER_NONE,	MAC_NUBUS},
+
 	/*
 	 *	Centris - just guessing again; maybe like Quadra
 	 */
 
-	{	MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC, MAC_NUBUS},
-	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC, MAC_NUBUS},
-	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	/* The C610 may or may not have SONIC.  We probe to make sure */
+	{	MAC_MODEL_C610, "Centris 610",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_C650, "Centris 650",   MAC_ADB_II,   MAC_VIA_QUADRA, MAC_SCSI_QUADRA,  MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_SONIC,	MAC_NUBUS},
+	{	MAC_MODEL_C660, "Centris 660AV", MAC_ADB_CUDA, MAC_VIA_QUADRA, MAC_SCSI_QUADRA3, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_MACE,		MAC_NUBUS},
 
 	/*
 	 *      Power books - seem similar to early Quadras ? (most have 030 though)
 	 */
 
-	{	MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB140,  "PowerBook 140",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB145,  "PowerBook 145",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 	/*	The PB150 has IDE, and IIci style VIA */
-	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_QUADRA, MAC_IDE_PB,	 MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB190,  "PowerBook 190",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_PB,   MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB150,  "PowerBook 150",   MAC_ADB_PB1, MAC_VIA_IIci,   MAC_SCSI_NONE, MAC_IDE_PB,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB160,  "PowerBook 160",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB165,  "PowerBook 165",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB165C, "PowerBook 165c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB170,  "PowerBook 170",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_OLD,  MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB180,  "PowerBook 180",   MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB180C, "PowerBook 180c",  MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB190,  "PowerBook 190cs", MAC_ADB_PB1, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_PB,	MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	/* These have onboard SONIC */
+	{	MAC_MODEL_PB520,  "PowerBook 520",   MAC_ADB_PB2, MAC_VIA_QUADRA, MAC_SCSI_NONE, MAC_IDE_NONE,	MAC_SCC_QUADRA,	MAC_ETHER_SONIC, MAC_NUBUS},
 
 	/*
 	 *      Power book Duos - similar to Power books, I hope
 	 */
 
-	{	MAC_MODEL_PB210,  "PowerBook Duo 210",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD,    MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB250,  "PowerBook Duo 250",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB280,  "PowerBook Duo 280",  MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
-	{	MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2,  MAC_VIA_QUADRA, MAC_SCSI_QUADRA, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	/* All of these might have onboard SONIC in the Dock but I'm not quite sure */
+	{	MAC_MODEL_PB210,  "PowerBook Duo 210",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB230,  "PowerBook Duo 230",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB250,  "PowerBook Duo 250",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB270C, "PowerBook Duo 270c", MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB280,  "PowerBook Duo 280",  MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
+	{	MAC_MODEL_PB280C, "PowerBook Duo 280c", MAC_ADB_PB2,  MAC_VIA_IIci, MAC_SCSI_OLD, MAC_IDE_NONE, MAC_SCC_QUADRA,	MAC_ETHER_NONE,	MAC_NUBUS},
 
 	/*
 	 *	Other stuff ??
@@ -508,7 +621,7 @@
 
 void mac_identify(void)
 {
-	struct mac_model *m=&mac_data_table[0];
+	struct mac_model *m;
 
 	/* Penguin data useful? */	
 	int model = mac_bi_data.id;
@@ -519,32 +632,23 @@
 		printk ("No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
 	}
 
-	printk ("Detected Macintosh model: %d \n", model);
-	
-	while(m->ident != -1)
-	{
-		if(m->ident == model)
+	macintosh_config = mac_data_table; 
+	for (m = macintosh_config ; m->ident != -1 ; m++) {
+		if (m->ident == model) {
+			macintosh_config = m;
 			break;
-		m++;
-	}
-	if(m->ident==-1)
-	{
-		printk("\nUnknown macintosh model %d, probably unsupported.\n", 
-			model);
-		model = MAC_MODEL_Q800;
-		printk("Defaulting to: Quadra800, model id %d\n", model);
-		printk("Please report this case to linux-mac68k@wave.lm.com\n");
-		m=&mac_data_table[0];
-		while(m->ident != -1)
-		{
-			if(m->ident == model)
-				break;
-			m++;
 		}
-		if(m->ident==-1)
-			panic("mac model config data corrupt!\n");
 	}
 
+	/* We need to pre-init the IOPs, if any. Otherwise */
+	/* the serial console won't work if the user had   */
+	/* the serial ports set to "Faster" mode in MacOS. */
+
+	iop_preinit();
+	mac_debug_init();
+
+	printk ("Detected Macintosh model: %d \n", model);
+
 	/*
 	 * Report booter data:
 	 */
@@ -566,12 +670,6 @@
 #endif
 
 	/*
-	 *	Save the pointer
-	 */
-
-	macintosh_config=m;
-
-	/*
 	 * TODO: set the various fields in macintosh_config->hw_present here!
 	 */
 	switch (macintosh_config->scsi_type) {
@@ -592,7 +690,10 @@
 	  break;
 
 	}
-	via_configure_base();
+	iop_init();
+	via_init();
+	oss_init();
+	psc_init();
 }
 
 void mac_report_hardware(void)
@@ -604,8 +705,133 @@
 {
 	strcpy(str,"Macintosh ");
 	strcat(str, macintosh_config->name);
-	if(mach_l2_flush && !(via_read(via2, vBufB)&VIA2B_vCDis))
-		strcat(str, "(+L2 cache)");
+}
+
+/*
+ *	The power switch - yes it's software!
+ */
+
+void mac_poweroff(void)
+{
+	/*
+	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
+	 * work using the ADB packet method.  --David Kilzer
+	 */
+
+	if (oss_present) {
+		oss_poweroff();
+	} else if (macintosh_config->adb_type == MAC_ADB_II) {
+		via_poweroff();
+	} else {
+		adb_poweroff();
+	}
+}
+
+/* 
+ * Not all Macs support software power down; for the rest, just 
+ * try the ROM reset vector ...
+ */
+void mac_reset(void)
+{
+	/*
+	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
+	 * work using the ADB packet method.  --David Kilzer
+	 */
+
+	if (macintosh_config->adb_type == MAC_ADB_II) {
+		unsigned long cpu_flags;
+
+		/* need ROMBASE in booter */
+		/* indeed, plus need to MAP THE ROM !! */
+
+		if (mac_bi_data.rombase == 0)
+			mac_bi_data.rombase = 0x40800000;
+
+		/* works on some */
+		rom_reset = (void *) (mac_bi_data.rombase + 0xa);
+
+		if (macintosh_config->ident == MAC_MODEL_SE30) {
+			/*
+			 * MSch: Machines known to crash on ROM reset ...
+			 */
+			printk("System halted.\n");
+			while(1);
+		} else {
+			save_flags(cpu_flags);
+			cli();
+
+			rom_reset();
+
+			restore_flags(cpu_flags);
+		}
+
+		/* We never make it this far... it usually panics above. */
+		printk ("Restart failed.  Please restart manually.\n");
+
+		/* XXX - delay do we need to spin here ? */
+		while(1);       /* Just in case .. */
+	} else if (macintosh_config->adb_type == MAC_ADB_IISI
+		|| macintosh_config->adb_type == MAC_ADB_CUDA) {
+		adb_hwreset();
+	} else if (CPU_IS_030) {
+
+		/* 030-specific reset routine.  The idea is general, but the
+		 * specific registers to reset are '030-specific.  Until I
+		 * have a non-030 machine, I can't test anything else.
+		 *  -- C. Scott Ananian <cananian@alumni.princeton.edu>
+		 */
+
+		unsigned long rombase = 0x40000000;
+
+		/* make a 1-to-1 mapping, using the transparent tran. reg. */
+		unsigned long virt = (unsigned long) mac_reset;
+		unsigned long phys = virt_to_phys(mac_reset);
+		unsigned long offset = phys-virt;
+		cli(); /* lets not screw this up, ok? */
+		__asm__ __volatile__(".chip 68030\n\t"
+				     "pmove %0,%/tt0\n\t"
+				     ".chip 68k"
+				     : : "m" ((phys&0xFF000000)|0x8777));
+		/* Now jump to physical address so we can disable MMU */
+		__asm__ __volatile__(
+                    ".chip 68030\n\t"
+		    "lea %/pc@(1f),%/a0\n\t"
+		    "addl %0,%/a0\n\t"/* fixup target address and stack ptr */
+		    "addl %0,%/sp\n\t" 
+		    "pflusha\n\t"
+		    "jmp %/a0@\n\t" /* jump into physical memory */
+		    "0:.long 0\n\t" /* a constant zero. */
+		    /* OK.  Now reset everything and jump to reset vector. */
+		    "1:\n\t"
+		    "lea %/pc@(0b),%/a0\n\t"
+		    "pmove %/a0@, %/tc\n\t" /* disable mmu */
+		    "pmove %/a0@, %/tt0\n\t" /* disable tt0 */
+		    "pmove %/a0@, %/tt1\n\t" /* disable tt1 */
+		    "movel #0, %/a0\n\t"
+		    "movec %/a0, %/vbr\n\t" /* clear vector base register */
+		    "movec %/a0, %/cacr\n\t" /* disable caches */
+		    "movel #0x0808,%/a0\n\t"
+		    "movec %/a0, %/cacr\n\t" /* flush i&d caches */
+		    "movew #0x2700,%/sr\n\t" /* set up status register */
+		    "movel %1@(0x0),%/a0\n\t"/* load interrupt stack pointer */
+		    "movec %/a0, %/isp\n\t" 
+		    "movel %1@(0x4),%/a0\n\t" /* load reset vector */
+		    "reset\n\t" /* reset external devices */
+		    "jmp %/a0@\n\t" /* jump to the reset vector */
+		    ".chip 68k"
+		    : : "r" (offset), "a" (rombase) : "a0");
+
+		/* should never get here */
+		sti(); /* sure, why not */
+		printk ("030 Restart failed.  Please restart manually.\n");
+		while(1);
+	} else {
+		/* We never make it here... The above shoule handle all cases. */
+		printk ("Restart failed.  Please restart manually.\n");
+
+		/* XXX - delay do we need to spin here ? */
+		while(1);       /* Just in case .. */
+	}
 }
 
 /*
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/debug.c linux/arch/m68k/mac/debug.c
--- v2.3.16/linux/arch/m68k/mac/debug.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/mac/debug.c	Sat Sep  4 13:06:41 1999
@@ -243,7 +243,7 @@
     }
 }
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(DEBUG_SERIAL)
 int mac_sccb_console_wait_key(struct console *co)
 {
     int i;
@@ -384,6 +384,16 @@
     mac_SCC_init_done = 1;
 }
 #endif /* DEBUG_SERIAL */
+
+void mac_init_scca_port( int cflag )
+{
+	mac_init_scc_port(cflag, 0);
+}
+
+void mac_init_sccb_port( int cflag )
+{
+	mac_init_scc_port(cflag, 1);
+}
 
 void __init mac_debug_init(void)
 {
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/iop.c linux/arch/m68k/mac/iop.c
--- v2.3.16/linux/arch/m68k/mac/iop.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/iop.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,725 @@
+/*
+ * I/O Processor (IOP) management
+ * Written and (C) 1999 by Joshua M. Thompson (funaho@jurai.org)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice and this list of conditions.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice and this list of conditions in the documentation and/or other
+ *    materials provided with the distribution.
+ */
+
+/*
+ * The IOP chips are used in the IIfx and some Quadras (900, 950) to manage
+ * serial and ADB. They are actually a 6502 processor and some glue logic.
+ *
+ * 990429 (jmt) - Initial implementation, just enough to knock the SCC IOP
+ *		  into compatible mode so nobody has to fiddle with the
+ *		  Serial Switch control panel anymore.
+ * 990603 (jmt) - Added code to grab the correct ISM IOP interrupt for OSS
+ *		  and non-OSS machines (at least I hope it's correct on a
+ *		  non-OSS machine -- someone with a Q900 or Q950 needs to
+ *		  check this.)
+ * 990605 (jmt) - Rearranged things a bit wrt IOP detection; iop_present is
+ *		  gone, IOP base addresses are now in an array and the
+ *		  globally-visible functions take an IOP number instead of an
+ *		  an actual base address.
+ * 990610 (jmt) - Finished the message passing framework and it seems to work.
+ *		  Sending _definately_ works; my adb-bus.c mods can send
+ *		  messages and receive the MSG_COMPLETED status back from the
+ *		  IOP. The trick now is figuring out the message formats.
+ * 990611 (jmt) - More cleanups. Fixed problem where unclaimed messages on a
+ *		  receive channel were never properly acknowledged. Bracketed
+ *		  the remaining debug printk's with #ifdef's and disabled
+ *		  debugging. I can now type on the console.
+ * 990612 (jmt) - Copyright notice added. Reworked the way replies are handled.
+ *		  It turns out that replies are placed back in the send buffer
+ *		  for that channel; messages on the receive channels are always
+ *		  unsolicited messages from the IOP (and our replies to them
+ *		  should go back in the receive channel.) Also added tracking
+ *		  of device names to the listener functions ala the interrupt
+ *		  handlers.
+ * 990729 (jmt) - Added passing of pt_regs structure to IOP handlers. This is
+ *		  used by the new unified ADB driver.
+ *
+ * TODO:
+ *
+ * o Something should be periodically checking iop_alive() to make sure the
+ *   IOP hasn't died.
+ * o Some of the IOP manager routines need better error checking and
+ *   return codes. Nothing major, just prettying up.
+ */
+
+/*
+ * -----------------------
+ * IOP Message Passing 101
+ * -----------------------
+ *
+ * The host talks to the IOPs using a rather simple message-passing scheme via
+ * a shared memory area in the IOP RAM. Each IOP has seven "channels"; each
+ * channel is conneced to a specific software driver on the IOP. For example
+ * on the SCC IOP there is one channel for each serial port. Each channel has
+ * an incoming and and outgoing message queue with a depth of one.
+ *
+ * A message is 32 bytes plus a state byte for the channel (MSG_IDLE, MSG_NEW,
+ * MSG_RCVD, MSG_COMPLETE). To send a message you copy the message into the
+ * buffer, set the state to MSG_NEW and signal the IOP by setting the IRQ flag
+ * in the IOP control to 1. The IOP will move the state to MSG_RCVD when it
+ * receives the message and then to MSG_COMPLETE when the message processing
+ * has completed. It is the host's responsibility at that point to read the
+ * reply back out of the send channel buffer and reset the channel state back
+ * to MSG_IDLE.
+ *
+ * To receive message from the IOP the same procedure is used except the roles
+ * are reversed. That is, the IOP puts message in the channel with a state of
+ * MSG_NEW, and the host receives the message and move its state to MSG_RCVD
+ * and then to MSG_COMPLETE when processing is completed and the reply (if any)
+ * has been placed back in the receive channel. The IOP will then reset the
+ * channel state to MSG_IDLE.
+ *
+ * Two sets of host interrupts are provided, INT0 and INT1. Both appear on one
+ * interrupt level; they are distinguished by a pair of bits in the IOP status
+ * register. The IOP will raise INT0 when one or more messages in the send
+ * channels have gone to the MSG_COMPLETE state and it will raise INT1 when one
+ * or more messages on the receive channels have gone to the MSG_NEW state.
+ *
+ * Since each channel handles only one message we have to implement a small
+ * interrupt-driven queue on our end. Messages to e sent are placed on the
+ * queue for sending and contain a pointer to an optional callback function.
+ * The handler for a message is called when the message state goes to
+ * MSG_COMPLETE.
+ *
+ * For receiving message we maintain a list of handler functions to call when
+ * a message is received on that IOP/channel combination. The handlers are
+ * called much like an interrupt handler and are passed a copy of the message
+ * from the IOP. The message state will be in MSG_RCVD while the handler runs;
+ * it is the handler's responsibility to call iop_complete_message() when
+ * finished; this function moves the message state to MSG_COMPLETE and signals
+ * the IOP. This two-step process is provided to allow the handler to defer
+ * message processing to a bottom-half handler if the processing will take
+ * a signifigant amount of time (handlers are called at interrupt time so they
+ * should execute quickly.)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/bootinfo.h> 
+#include <asm/macintosh.h> 
+#include <asm/macints.h> 
+#include <asm/mac_iop.h>
+#include <asm/mac_oss.h>
+
+/*#define DEBUG_IOP*/
+
+/* Set to nonezero if the IOPs are present. Set by iop_init() */
+
+int iop_scc_present,iop_ism_present;
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * sneaky reuse of the PROC_MAC_VIA inode. It's not needed by via.c
+ * anymore so we'll use it to debut the IOPs.
+ */
+
+int iop_get_proc_info(char *, char **, off_t, int, int);
+
+static struct proc_dir_entry proc_mac_iop = {
+	PROC_MAC_VIA, 7, "mac_iop",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations,
+	&iop_get_proc_info
+};
+
+#endif /* CONFIG_PROC_FS */
+
+/* structure for tracking channel listeners */
+
+struct listener {
+	const char *devname;
+	void (*handler)(struct iop_msg *, struct pt_regs *);
+};
+
+/*
+ * IOP structures for the two IOPs
+ *
+ * The SCC IOP controls both serial ports (A and B) as its two functions.
+ * The ISM IOP controls the SWIM (floppy drive) and ADB.
+ */
+
+static volatile struct mac_iop *iop_base[NUM_IOPS];
+
+/*
+ * IOP message queues
+ */
+
+static struct iop_msg iop_msg_pool[NUM_IOP_MSGS];
+static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN];
+static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN];
+
+void iop_ism_irq(int, void *, struct pt_regs *);
+
+extern void oss_irq_enable(int);
+
+/*
+ * Private access functions
+ */
+
+static __inline__ void iop_loadaddr(volatile struct mac_iop *iop, __u16 addr)
+{
+	iop->ram_addr_lo = addr;
+	iop->ram_addr_hi = addr >> 8;
+}
+
+static __inline__ __u8 iop_readb(volatile struct mac_iop *iop, __u16 addr)
+{
+	iop->ram_addr_lo = addr;
+	iop->ram_addr_hi = addr >> 8;
+	return iop->ram_data;
+}
+
+static __inline__ void iop_writeb(volatile struct mac_iop *iop, __u16 addr, __u8 data)
+{
+	iop->ram_addr_lo = addr;
+	iop->ram_addr_hi = addr >> 8;
+	iop->ram_data = data;
+}
+
+static __inline__ void iop_stop(volatile struct mac_iop *iop)
+{
+	iop->status_ctrl &= ~IOP_RUN;
+}
+
+static __inline__ void iop_start(volatile struct mac_iop *iop)
+{
+	iop->status_ctrl = IOP_RUN | IOP_AUTOINC;
+}
+
+static __inline__ void iop_bypass(volatile struct mac_iop *iop)
+{
+	iop->status_ctrl |= IOP_BYPASS;
+}
+
+static __inline__ void iop_interrupt(volatile struct mac_iop *iop)
+{
+	iop->status_ctrl |= IOP_IRQ;
+}
+
+static int iop_alive(volatile struct mac_iop *iop)
+{
+	int retval;
+
+	retval = (iop_readb(iop, IOP_ADDR_ALIVE) == 0xFF);
+	iop_writeb(iop, IOP_ADDR_ALIVE, 0);
+	return retval;
+}
+
+static struct iop_msg *iop_alloc_msg(void)
+{
+	int i;
+	ulong cpu_flags;
+
+	save_flags(cpu_flags);
+	cli();
+
+	for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
+		if (iop_msg_pool[i].status == IOP_MSGSTATUS_UNUSED) {
+			iop_msg_pool[i].status = IOP_MSGSTATUS_WAITING;
+			restore_flags(cpu_flags);
+			return &iop_msg_pool[i];
+		}
+	}
+
+	restore_flags(cpu_flags);
+	return NULL;
+}
+
+static void iop_free_msg(struct iop_msg *msg)
+{
+	msg->status = IOP_MSGSTATUS_UNUSED;
+}
+
+/*
+ * This is called by the startup code before anything else. Its purpose
+ * is to find and initalize the IOPs early in the boot sequence, so that
+ * the serial IOP can be placed into bypass mode _before_ we try to
+ * initialize the serial console.
+ */
+
+void __init iop_preinit(void)
+{
+	if (macintosh_config->scc_type == MAC_SCC_IOP) {
+		if (macintosh_config->ident == MAC_MODEL_IIFX) {
+			iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_IIFX;
+		} else {
+			iop_base[IOP_NUM_SCC] = (struct mac_iop *) SCC_IOP_BASE_QUADRA;
+		}
+		iop_base[IOP_NUM_SCC]->status_ctrl = 0x87;
+		iop_scc_present = 1;
+	} else {
+		iop_base[IOP_NUM_SCC] = NULL;
+		iop_scc_present = 0;
+	}
+	if (macintosh_config->adb_type == MAC_ADB_IOP) {
+		if (macintosh_config->ident == MAC_MODEL_IIFX) {
+			iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_IIFX;
+		} else {
+			iop_base[IOP_NUM_ISM] = (struct mac_iop *) ISM_IOP_BASE_QUADRA;
+		}
+		iop_base[IOP_NUM_SCC]->status_ctrl = 0;
+		iop_ism_present = 1;
+	} else {
+		iop_base[IOP_NUM_ISM] = NULL;
+		iop_ism_present = 0;
+	}
+}
+
+/*
+ * Initialize the IOPs, if present.
+ */
+
+void __init iop_init(void)
+{
+	int i;
+
+	if (iop_scc_present) {
+		printk("IOP: detected SCC IOP at %p\n", iop_base[IOP_NUM_SCC]);
+	}
+	if (iop_ism_present) {
+		printk("IOP: detected ISM IOP at %p\n", iop_base[IOP_NUM_ISM]);
+		iop_start(iop_base[IOP_NUM_ISM]);
+		iop_alive(iop_base[IOP_NUM_ISM]); /* clears the alive flag */
+	}
+
+	/* Make the whole pool available and empty the queues */
+
+	for (i = 0 ; i < NUM_IOP_MSGS ; i++) {
+		iop_msg_pool[i].status = IOP_MSGSTATUS_UNUSED;
+	}
+
+	for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+		iop_send_queue[IOP_NUM_SCC][i] = 0;
+		iop_send_queue[IOP_NUM_ISM][i] = 0;
+		iop_listeners[IOP_NUM_SCC][i].devname = NULL;
+		iop_listeners[IOP_NUM_SCC][i].handler = NULL;
+		iop_listeners[IOP_NUM_ISM][i].devname = NULL;
+		iop_listeners[IOP_NUM_ISM][i].handler = NULL;
+	}
+
+#ifdef CONFIG_PROC_FS
+	proc_register(&proc_root, &proc_mac_iop);
+#endif
+}
+
+/*
+ * Register the interrupt handler for the IOPs.
+ * TODO: might be wrong for non-OSS machines. Anyone?
+ */
+
+void __init iop_register_interrupts(void)
+{
+	if (iop_ism_present) {
+		if (oss_present) {
+			request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq,
+					IRQ_FLG_LOCK, "ISM IOP",
+					(void *) IOP_NUM_ISM);
+			oss_irq_enable(IRQ_MAC_ADB);
+		} else {
+			request_irq(IRQ_VIA2_0, iop_ism_irq,
+					IRQ_FLG_LOCK|IRQ_FLG_FAST, "ISM IOP",
+					(void *) IOP_NUM_ISM);
+		}
+		if (!iop_alive(iop_base[IOP_NUM_ISM])) {
+			printk("IOP: oh my god, they killed the ISM IOP!\n");
+		} else {
+			printk("IOP: the ISM IOP seems to be alive.\n");
+		}
+	}
+}
+
+/*
+ * Register or unregister a listener for a specific IOP and channel
+ *
+ * If the handler pointer is NULL the current listener (if any) is
+ * unregistered. Otherwise the new listener is registered provided
+ * there is no existing listener registered.
+ */
+
+int iop_listen(uint iop_num, uint chan,
+		void (*handler)(struct iop_msg *, struct pt_regs *),
+		const char *devname)
+{
+	if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
+	if (chan >= NUM_IOP_CHAN) return -EINVAL;
+	if (iop_listeners[iop_num][chan].handler && handler) return -EINVAL;
+	iop_listeners[iop_num][chan].devname = devname;
+	iop_listeners[iop_num][chan].handler = handler;
+	return 0;
+}
+
+/*
+ * Complete reception of a message, which just means copying the reply
+ * into the buffer, setting the channel state to MSG_COMPLETE and
+ * notifying the IOP.
+ */
+
+void iop_complete_message(struct iop_msg *msg)
+{
+	int iop_num = msg->iop_num;
+	int chan = msg->channel;
+	int i,offset;
+
+#ifdef DEBUG_IOP
+	printk("iop_complete(%p): iop %d chan %d\n", msg, msg->iop_num, msg->channel);
+#endif
+
+	offset = IOP_ADDR_RECV_MSG + (msg->channel * IOP_MSG_LEN);
+
+	for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+		iop_writeb(iop_base[iop_num], offset, msg->reply[i]);
+	}
+
+	iop_writeb(iop_base[iop_num],
+		   IOP_ADDR_RECV_STATE + chan, IOP_MSG_COMPLETE);
+	iop_interrupt(iop_base[msg->iop_num]);
+
+	iop_free_msg(msg);
+}
+
+/*
+ * Actually put a message into a send channel buffer
+ */
+
+static void iop_do_send(struct iop_msg *msg)
+{
+	volatile struct mac_iop *iop = iop_base[msg->iop_num];
+	int i,offset;
+
+	offset = IOP_ADDR_SEND_MSG + (msg->channel * IOP_MSG_LEN);
+
+	for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+		iop_writeb(iop, offset, msg->message[i]);
+	}
+
+	iop_writeb(iop, IOP_ADDR_SEND_STATE + msg->channel, IOP_MSG_NEW);
+
+	iop_interrupt(iop);
+}
+
+/*
+ * Handle sending a message on a channel that
+ * has gone into the IOP_MSG_COMPLETE state.
+ */
+
+static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
+{
+	volatile struct mac_iop *iop = iop_base[iop_num];
+	struct iop_msg *msg,*msg2;
+	int i,offset;
+
+#ifdef DEBUG_IOP
+	printk("iop_handle_send: iop %d channel %d\n", iop_num, chan);
+#endif
+
+	iop_writeb(iop, IOP_ADDR_SEND_STATE + chan, IOP_MSG_IDLE);
+
+	if (!(msg = iop_send_queue[iop_num][chan])) return;
+
+	msg->status = IOP_MSGSTATUS_COMPLETE;
+	offset = IOP_ADDR_SEND_MSG + (chan * IOP_MSG_LEN);
+	for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+		msg->reply[i] = iop_readb(iop, offset);
+	}
+	if (msg->handler) (*msg->handler)(msg, regs);
+	msg2 = msg;
+	msg = msg->next;
+	iop_free_msg(msg2);
+
+	iop_send_queue[iop_num][chan] = msg;
+	if (msg) iop_do_send(msg);
+}
+
+/*
+ * Handle reception of a message on a channel that has
+ * gone into the IOP_MSG_NEW state.
+ */
+
+static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
+{
+	volatile struct mac_iop *iop = iop_base[iop_num];
+	int i,offset;
+	struct iop_msg *msg;
+
+#ifdef DEBUG_IOP
+	printk("iop_handle_recv: iop %d channel %d\n", iop_num, chan);
+#endif
+
+	msg = iop_alloc_msg();
+	msg->iop_num = iop_num;
+	msg->channel = chan;
+	msg->status = IOP_MSGSTATUS_UNSOL;
+	msg->handler = iop_listeners[iop_num][chan].handler;
+
+	offset = IOP_ADDR_RECV_MSG + (chan * IOP_MSG_LEN);
+
+	for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
+		msg->message[i] = iop_readb(iop, offset);
+	}
+
+	iop_writeb(iop, IOP_ADDR_RECV_STATE + chan, IOP_MSG_RCVD);
+
+	/* If there is a listener, call it now. Otherwise complete */
+	/* the message ourselves to avoid possible stalls.         */
+
+	if (msg->handler) {
+		(*msg->handler)(msg, regs);
+	} else {
+#ifdef DEBUG_IOP
+		printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan);
+		printk("iop_handle_recv:");
+		for (i = 0 ; i < IOP_MSG_LEN ; i++) {
+			printk(" %02X", (uint) msg->message[i]);
+		}
+		printk("\n");
+#endif
+		iop_complete_message(msg);
+	}
+}
+
+/*
+ * Send a message
+ * 
+ * The message is placed at the end of the send queue. Afterwards if the
+ * channel is idle we force an immediate send of the next message in the
+ * queue.
+ */
+
+int iop_send_message(uint iop_num, uint chan, void *privdata,
+		      uint msg_len, __u8 *msg_data,
+		      void (*handler)(struct iop_msg *, struct pt_regs *))
+{
+	struct iop_msg *msg, *q;
+
+	if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
+	if (chan >= NUM_IOP_CHAN) return -EINVAL;
+	if (msg_len > IOP_MSG_LEN) return -EINVAL;
+
+	msg = iop_alloc_msg();
+	if (!msg) return -ENOMEM;
+
+	msg->next = NULL;
+	msg->status = IOP_MSGSTATUS_WAITING;
+	msg->iop_num = iop_num;
+	msg->channel = chan;
+	msg->caller_priv = privdata;
+	memcpy(msg->message, msg_data, msg_len);
+	msg->handler = handler;
+
+	if (!(q = iop_send_queue[iop_num][chan])) {
+		iop_send_queue[iop_num][chan] = msg;
+	} else {
+		while (q->next) q = q->next;
+		q->next = msg;
+	}
+
+	if (iop_readb(iop_base[iop_num],
+	    IOP_ADDR_SEND_STATE + chan) == IOP_MSG_IDLE) {
+		iop_do_send(msg);
+	}
+
+	return 0;
+}
+
+/*
+ * Upload code to the shared RAM of an IOP.
+ */
+
+void iop_upload_code(uint iop_num, __u8 *code_start,
+		     uint code_len, __u16 shared_ram_start)
+{
+	if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return;
+
+	iop_loadaddr(iop_base[iop_num], shared_ram_start);
+	
+	while (code_len--) {
+		iop_base[iop_num]->ram_data = *code_start++;
+	}
+}
+
+/*
+ * Download code from the shared RAM of an IOP.
+ */
+
+void iop_download_code(uint iop_num, __u8 *code_start,
+		       uint code_len, __u16 shared_ram_start)
+{
+	if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return;
+
+	iop_loadaddr(iop_base[iop_num], shared_ram_start);
+	
+	while (code_len--) {
+		*code_start++ = iop_base[iop_num]->ram_data;
+	}
+}
+
+/*
+ * Compare the code in the shared RAM of an IOP with a copy in system memory
+ * and return 0 on match or the first nonmatching system memory address on
+ * failure.
+ */
+
+__u8 *iop_compare_code(uint iop_num, __u8 *code_start,
+		       uint code_len, __u16 shared_ram_start)
+{
+	if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return code_start;
+
+	iop_loadaddr(iop_base[iop_num], shared_ram_start);
+	
+	while (code_len--) {
+		if (*code_start != iop_base[iop_num]->ram_data) {
+			return code_start;
+		}
+		code_start++;
+	}
+	return (__u8 *) 0;
+}
+
+/*
+ * Handle an ISM IOP interrupt
+ */
+
+void iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	uint iop_num = (uint) dev_id;
+	volatile struct mac_iop *iop = iop_base[iop_num];
+	int i,state;
+
+#ifdef DEBUG_IOP
+	printk("iop_ism_irq: status = %02X\n", (uint) iop->status_ctrl);
+#endif
+
+	/* INT0 indicates a state change on an outgoing message channel */
+
+	if (iop->status_ctrl & IOP_INT0) {
+		iop->status_ctrl = IOP_INT0 | IOP_RUN | IOP_AUTOINC;
+#ifdef DEBUG_IOP
+		printk("iop_ism_irq: new status = %02X, send states",
+			(uint) iop->status_ctrl);
+#endif
+		for (i = 0 ; i < NUM_IOP_CHAN  ; i++) {
+			state = iop_readb(iop, IOP_ADDR_SEND_STATE + i);
+#ifdef DEBUG_IOP
+			printk(" %02X", state);
+#endif
+			if (state == IOP_MSG_COMPLETE) {
+				iop_handle_send(iop_num, i, regs);
+			}
+		}
+#ifdef DEBUG_IOP
+		printk("\n");
+#endif
+	}
+
+	if (iop->status_ctrl & IOP_INT1) {	/* INT1 for incoming msgs */
+		iop->status_ctrl = IOP_INT1 | IOP_RUN | IOP_AUTOINC;
+#ifdef DEBUG_IOP
+		printk("iop_ism_irq: new status = %02X, recv states",
+			(uint) iop->status_ctrl);
+#endif
+		for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+			state = iop_readb(iop, IOP_ADDR_RECV_STATE + i);
+#ifdef DEBUG_IOP
+			printk(" %02X", state);
+#endif
+			if (state == IOP_MSG_NEW) {
+				iop_handle_recv(iop_num, i, regs);
+			}
+		}
+#ifdef DEBUG_IOP
+		printk("\n");
+#endif
+	}
+
+}
+
+#ifdef CONFIG_PROC_FS
+
+char *iop_chan_state(int state)
+{
+	switch(state) {
+		case IOP_MSG_IDLE	: return "idle      ";
+		case IOP_MSG_NEW	: return "new       ";
+		case IOP_MSG_RCVD	: return "received  ";
+		case IOP_MSG_COMPLETE	: return "completed ";
+		default			: return "unknown   ";
+	}
+}
+
+int iop_dump_one_iop(char *buf, int iop_num, char *iop_name)
+{
+	int i,len = 0;
+	volatile struct mac_iop *iop = iop_base[iop_num];
+
+	len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name);
+	len += sprintf(buf+len, "##  send_state  recv_state  device\n");
+	len += sprintf(buf+len, "------------------------------------------------\n");
+	for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
+		len += sprintf(buf+len, "%2d  %10s  %10s  %s\n", i,
+			iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)),
+			iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)),
+			iop_listeners[iop_num][i].handler?
+				      iop_listeners[iop_num][i].devname : "");
+			
+	}
+	len += sprintf(buf+len, "\n");
+	return len;
+}
+ 
+int iop_get_proc_info(char *buf, char **start, off_t pos, int count, int wr)
+{
+	int len, cnt;
+
+	cnt = 0;
+	len =  sprintf(buf, "IOPs detected:\n\n");
+
+	if (iop_scc_present) {
+		len += sprintf(buf+len, "SCC IOP (%p): status %02X\n",
+				iop_base[IOP_NUM_SCC],
+				(uint) iop_base[IOP_NUM_SCC]->status_ctrl);
+	}
+	if (iop_ism_present) {
+		len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n",
+				iop_base[IOP_NUM_ISM],
+				(uint) iop_base[IOP_NUM_ISM]->status_ctrl);
+	}
+
+	if (iop_scc_present) {
+		len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC");
+
+	}
+
+	if (iop_ism_present) {
+		len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM");
+
+	}
+
+	if (len >= pos) {
+		if (!*start) {
+			*start = buf + pos;
+			cnt = len - pos;
+		} else {
+			cnt += len;
+		}
+	}
+	return (count > cnt) ? cnt : count;
+}
+#endif /* CONFIG_PROC_FS */
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/mac_ksyms.c linux/arch/m68k/mac/mac_ksyms.c
--- v2.3.16/linux/arch/m68k/mac/mac_ksyms.c	Wed Sep  2 09:39:18 1998
+++ linux/arch/m68k/mac/mac_ksyms.c	Sat Sep  4 13:06:41 1999
@@ -1,7 +1,8 @@
 #include <linux/module.h>
 #include <asm/ptrace.h>
 #include <asm/traps.h>
-/* Hook for mouse driver */
-extern void (*adb_mouse_interrupt_hook) (char *);
 
-EXPORT_SYMBOL(adb_mouse_interrupt_hook);
+/* Says whether we're using A/UX interrupts or not */
+extern int via_alt_mapping;
+
+EXPORT_SYMBOL(via_alt_mapping);
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/mac_penguin.S linux/arch/m68k/mac/mac_penguin.S
--- v2.3.16/linux/arch/m68k/mac/mac_penguin.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/mac_penguin.S	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,75 @@
+.byte \
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0xFF,0xFF,0x0F,0xF0,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x00,0xFF,0xFF,0x0F,0xFF,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xF0,0x0F,0xFF,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x0F,0x0F,0xFF,0xF0,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x0F,0xF0,0x00,0x00,0xFF,0xF0,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x0F,0xF0,0xFF,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xFF,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0xF0,0x00,0x00,\
+0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0xF0,0x00,0x00,\
+0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x0F,0xF0,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xF0,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,\
+0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,\
+0x0F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,\
+0x0F,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0xFF,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xF0,0x00,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0x00,0x0F,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/macboing.c linux/arch/m68k/mac/macboing.c
--- v2.3.16/linux/arch/m68k/mac/macboing.c	Tue Jan  5 11:20:43 1999
+++ linux/arch/m68k/mac/macboing.c	Sat Sep  4 13:06:41 1999
@@ -91,14 +91,8 @@
 			mac_special_bell = mac_quadra_start_bell;
 			mac_asc_samplespersec = 22150;
 			break;	
-		case MAC_MODEL_Q650:
-		case MAC_MODEL_Q700:
-		case MAC_MODEL_Q800:
-		case MAC_MODEL_Q900:
-		case MAC_MODEL_Q950:
-			/*
-			 * Currently not implemented!
-			 */
+		case MAC_MODEL_C660:
+		case MAC_MODEL_Q840:
 			/*
 			 * The Quadra 660AV and 840AV use the "Singer" custom ASIC for sound I/O.
 			 * It appears to be similar to the "AWACS" custom ASIC in the Power Mac 
@@ -126,6 +120,22 @@
 			 */
 			mac_special_bell = mac_av_start_bell;
 			break;
+		case MAC_MODEL_Q650:
+		case MAC_MODEL_Q700:
+		case MAC_MODEL_Q800:
+		case MAC_MODEL_Q900:
+		case MAC_MODEL_Q950:
+			/*
+			 * Currently not implemented!
+			 */
+			mac_special_bell = NULL;
+			break;
+		default:
+			/*
+			 * Every switch needs a default
+			 */
+			mac_special_bell = NULL;
+			break;
 	}
 
 	/* 
@@ -154,6 +164,12 @@
 	__u32 cfreq = ( freq << 5 ) / 468;
 	__u32 flags;
 	int i;
+
+	if ( mac_special_bell == NULL )
+	{
+		/* Do nothing */
+		return;
+	}
 
 	if ( !mac_asc_inited )
 		mac_init_asc();
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c
--- v2.3.16/linux/arch/m68k/mac/macints.c	Tue Jan  5 11:20:43 1999
+++ linux/arch/m68k/mac/macints.c	Sat Sep  4 13:06:41 1999
@@ -7,8 +7,8 @@
  * interrupts with exception vectors 0x19-0x1f). The following interrupt levels
  * are used:
  *	1	- VIA1
- *		  - slot 0: one second interrupt
- *		  - slot 1: VBlank
+ *		  - slot 0: one second interrupt (CA2)
+ *		  - slot 1: VBlank (CA1)
  *		  - slot 2: ADB data ready (SR full)
  *		  - slot 3: ADB data  (CB2)
  *		  - slot 4: ADB clock (CB1)
@@ -16,57 +16,103 @@
  *		  - slot 6: timer 1
  *		  - slot 7: status of IRQ; signals 'any enabled int.'
  *
- *	2	- VIA2, RBV or OSS
- *		  - slot 0: SCSI DRQ
- *		  - slot 1: NUBUS IRQ
- *		  - slot 3: SCSI IRQ
- *
- *	4	- SCC
- *		  - subdivided into Channel B and Channel A interrupts 
- *
- *	6	- Off switch (??)
- *
- *	7	- Debug output
- *
- * AV Macs only, handled by PSC:
- *
- *	3	- MACE ethernet IRQ (DMA complete on level 4)
- *
- *	5	- DSP ?? 
- *
- * Using the autovector irq numbers for Linux/m68k hardware interrupts without
- * the IRQ_MACHSPEC bit set would interfere with the general m68k interrupt 
- * handling in kernel versions 2.0.x, so the following strategy is used:
- *
- * - mac_init_IRQ installs the low-level entry points for the via1 and via2 
- *   exception vectors and the corresponding handlers (C functions); these 
- *   entry points just add the machspec bit and call the handlers proper.
- *   (in principle, the C functions can be installed as the exception vectors 
- *   directly, as they are hardcoded anyway; that's the current method). 
- *
- * - via[12]_irq determine what interrupt sources have triggered the interrupt,
- *   and call the corresponding device interrupt handlers. 
- *   (currently, via1_irq and via2_irq just call via_irq, passing the via base
- *   address. RBV interrupts are handled by (you guessed it) rbv_irq).
- *   Some interrupt functions want to have the interrupt number passed, so 
- *   via_irq and rbv_irq need to generate the 'fake' numbers from scratch.
- *
- * - for the request/free/enable/disable business, interrupt sources are 
- *   numbered internally (suggestion: keep irq 0-7 unused :-). One bit in the 
- *   irq number specifies the via# to use, i.e. via1 interrupts are 8-16, 
- *   via2 interrupts 17-32, rbv interrupts ...
- *   The device interrupt table and the irq_enable bitmap is maintained by 
- *   the machspec interrupt code; all device drivers should only use these 
- *   functions ! 
- *
- * - For future porting to version 2.1 (and removing of the machspec bit) it 
- *   should be sufficient to use the same numbers (everything > 7 is assumed 
- *   to be machspec, according to Jes!).
+ *	2	- VIA2 or RBV
+ *		  - slot 0: SCSI DRQ (CA2)
+ *		  - slot 1: NUBUS IRQ (CA1) need to read port A to find which
+ *		  - slot 2: /EXP IRQ (only on IIci)
+ *		  - slot 3: SCSI IRQ (CB2)
+ *		  - slot 4: ASC IRQ (CB1)
+ *		  - slot 5: timer 2 (not on IIci)
+ *		  - slot 6: timer 1 (not on IIci)
+ *		  - slot 7: status of IRQ; signals 'any enabled int.'
+ *
+ *	2	- OSS (IIfx only?)
+ *		  - slot 0: SCSI interrupt
+ *		  - slot 1: Sound interrupt
+ *
+ * Levels 3-6 vary by machine type. For VIA or RBV Macintohes:
+ *
+ *	3	- unused (?)
+ *
+ *	4	- SCC (slot number determined by reading RR3 on the SSC itself)
+ *		  - slot 0: SCC channel A
+ *		  - slot 1: SCC channel B
+ *
+ *	5	- unused (?)
+ *		  [serial errors or special conditions seem to raise level 6
+ *		  interrupts on some models (LC4xx?)]
+ *
+ *	6	- off switch (?)
+ *
+ * For OSS Macintoshes (IIfx only at this point):
+ *
+ *	3	- Nubus interrupt
+ *		  - slot 0: Slot $9
+ *		  - slot 1: Slot $A
+ *		  - slot 2: Slot $B
+ *		  - slot 3: Slot $C
+ *		  - slot 4: Slot $D
+ *		  - slot 5: Slot $E
+ *
+ *	4	- SCC IOP
+ *		  - slot 0: SCC channel A
+ *		  - slot 1: SCC channel B
+ *
+ *	5	- ISM IOP (ADB?)
+ *
+ *	6	- unused
+ *
+ * For PSC Macintoshes (660AV, 840AV):
+ *
+ *	3	- PSC level 3
+ *		  - slot 0: MACE
+ *
+ *	4	- PSC level 4
+ *		  - slot 1: SCC channel A interrupt
+ *		  - slot 2: SCC channel B interrupt
+ *		  - slot 3: MACE DMA
+ *
+ *	5	- PSC level 5
+ *
+ *	6	- PSC level 6
+ *
+ * Finally we have good 'ole level 7, the non-maskable interrupt:
+ *
+ *	7	- NMI (programmer's switch on the back of some Macs)
+ *		  Also RAM parity error on models which support it (IIc, IIfx?)
+ *
+ * The current interrupt logic looks something like this:
+ *
+ * - We install dispatchers for the autovector interrupts (1-7). These
+ *   dispatchers are responsible for querying the hardware (the
+ *   VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
+ *   this information a machspec interrupt number is generated by placing the
+ *   index of the interrupt hardware into the low three bits and the original
+ *   autovector interrupt number in the upper 5 bits. The handlers for the
+ *   resulting machspec interrupt are then called.
+ *
+ * - Nubus is a special case because its interrupts are hidden behind two
+ *   layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
+ *   which translates to IRQ number 17. In this spot we install _another_
+ *   dispatcher. This dispatcher finds the interrupting slot number (9-F) and
+ *   then forms a new machspec interrupt number as above with the slot number
+ *   minus 9 in the low three bits and the pseudo-level 7 in the upper five
+ *   bits.  The handlers for this new machspec interrupt number are then
+ *   called. This puts Nubus interrupts into the range 56-62.
+ *
+ * - We support "fast" and "slow" handlers, just like the Amiga port. The
+ *   fast handlers are called first and with all interrupts disabled. They
+ *   are expected to execute quickly (hence the name). The slow handlers are
+ *   called last with interrupts enabled and the interrupt level restored.
+ *   They must therefore be reentrant.
+ *
+ * - Drivers should never try to request autovector interrupt numbers. It
+ *   won't work.
  *
  *   TODO:
- * - integrate Nubus interrupts in request/free_irq
  *
- * - 
+ *   o Perhaps build some intelligence into mac_SCC_handler(); we could check
+ *     the SCC ourselves and only call the handler for the appopriate channel.
  */
 
 #include <linux/config.h>
@@ -82,124 +128,53 @@
 #include <asm/traps.h>
 #include <asm/machw.h>
 #include <asm/macintosh.h>
-#include "via6522.h"
+#include <asm/mac_via.h>
+#include <asm/mac_psc.h>
 
 #include <asm/macints.h>
 
 /*
- * Interrupt handler and parameter types
- */
-struct irqhandler {
-	void	(*handler)(int, void *, struct pt_regs *);
-	void	*dev_id;
-};
-
-struct irqparam {
-	unsigned long	flags;
-	const char	*devname;
-};
-
-struct irqflags {
-        unsigned int disabled;
-	unsigned int pending;
-};
-
-/*
- * Array with irq's and their parameter data. 
- */
-static struct irqhandler  via1_handler[8];
-static struct irqhandler  via2_handler[8];
-static struct irqhandler   rbv_handler[8];
-static struct irqhandler  psc3_handler[8];
-static struct irqhandler   scc_handler[8];
-static struct irqhandler  psc5_handler[8];
-static struct irqhandler  psc6_handler[8];
-static struct irqhandler nubus_handler[8];
-
-static struct irqhandler *handler_table[8];
-
-/*
- * This array hold the rest of parameters of int handlers: type
- * (slow,fast,prio) and the name of the handler. These values are only
- * accessed from C
- */
-static struct irqparam  via1_param[8];
-static struct irqparam  via2_param[8];
-static struct irqparam   rbv_param[8];
-static struct irqparam  psc3_param[8];
-static struct irqparam   scc_param[8];
-static struct irqparam  psc5_param[8];
-static struct irqparam  psc6_param[8];
-static struct irqparam nubus_param[8];
-
-static struct irqparam *param_table[8];
-
-/*
- * This array holds the 'disabled' and 'pending' software flags maintained
- * by mac_{enable,disable}_irq and the generic via_irq function.
+ * VIA/RBV hooks
  */
 
-static struct irqflags irq_flags[8];
+extern void via_init(void);
+extern void via_register_interrupts(void);
+extern void via_irq_enable(int);
+extern void via_irq_disable(int);
+extern void via_irq_clear(int);
+extern int  via_irq_pending(int);
 
 /*
- * This array holds the pointers to the various VIA or other interrupt 
- * controllers, indexed by interrupt level
+ * OSS hooks
  */
 
-static volatile unsigned char *via_table[8];
-
-/*
- * Arrays with irq statistics
- */
-static unsigned long via1_irqs[8];
-static unsigned long via2_irqs[8];
-static unsigned long rbv_irqs[8];
-static unsigned long psc3_irqs[8];
-static unsigned long scc_irqs[8];
-static unsigned long psc5_irqs[8];
-static unsigned long psc6_irqs[8];
-static unsigned long nubus_irqs[8];
-
-static unsigned long *mac_irqs[8];
-
-/*
- * Some special nutcases ...
- */
+extern int oss_present;
 
-static unsigned long mac_ide_irqs = 0;
-static unsigned long nubus_stuck_events = 0;
+extern void oss_init(void);
+extern void oss_register_interrupts(void);
+extern void oss_irq_enable(int);
+extern void oss_irq_disable(int);
+extern void oss_irq_clear(int);
+extern int  oss_irq_pending(int);
 
 /*
- * VIA/RBV/OSS/PSC register base pointers
+ * PSC hooks
  */
 
-volatile unsigned char *via2_regp=(volatile unsigned char *)VIA2_BAS;
-volatile unsigned char *rbv_regp=(volatile unsigned char *)VIA2_BAS_IIci;
-volatile unsigned char *oss_regp=(volatile unsigned char *)OSS_BAS;
-volatile unsigned char *psc_regp=(volatile unsigned char *)PSC_BAS;
-
-/*
- * Flags to control via2 / rbv behaviour
- */ 
-
-static int via2_is_rbv = 0;
-static int via2_is_oss = 0;
-static int rbv_clear = 0;
+extern int psc_present;
 
-/* fake VIA2 to OSS bit mapping */
-static int oss_map[8] = {2, 7, 0, 1, 3, 4, 5};
-
-void oss_irq(int irq, void *dev_id, struct pt_regs *regs);
-static void oss_do_nubus(int irq, void *dev_id, struct pt_regs *regs);
-
-/* PSC ints */
-void psc_irq(int irq, void *dev_id, struct pt_regs *regs);
+extern void psc_init(void);
+extern void psc_register_interrupts(void);
+extern void psc_irq_enable(int);
+extern void psc_irq_disable(int);
+extern void psc_irq_clear(int);
+extern int  psc_irq_pending(int);
 
 /*
- * PSC hooks
+ * IOP hooks
  */
 
-extern void psc_init(void);
+extern void iop_register_interrupts(void);
 
 /*
  * console_loglevel determines NMI handler function
@@ -207,656 +182,317 @@
 
 extern int console_loglevel;
 
-/*
- * ADB test hooks
- */
-extern int in_keybinit;
-void adb_queue_poll(void);
-
-/* Defined in entry.S; only increments 'num_spurious' */
-asmlinkage void bad_interrupt(void);
-
-void nubus_wtf(int slot, void *via, struct pt_regs *regs);
-
-void mac_nmi_handler(int irq, void *dev_id, struct pt_regs *regs);
-void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs);
+extern void mac_bang(int, void *, struct pt_regs *);
 
-static void via_do_nubus(int slot, void *via, struct pt_regs *regs);
+void mac_nmi_handler(int, void *, struct pt_regs *);
+void mac_SCC_handler(int, void *, struct pt_regs *);
 
 /* #define DEBUG_MACINTS */
 
-#define DEBUG_SPURIOUS
-#define DEBUG_NUBUS_SPURIOUS
-#define DEBUG_NUBUS_INT
-
-/* #define DEBUG_VIA */
-#define DEBUG_VIA_NUBUS
-
 void mac_init_IRQ(void)
 {
-        int i;
-
 #ifdef DEBUG_MACINTS
-	printk("Mac interrupt stuff initializing ...\n");
+	printk("mac_init_IRQ(): Setting things up...\n");
 #endif
-
-	via2_regp = (unsigned char *)VIA2_BAS;
-	rbv_regp  = (unsigned char *)VIA2_BAS_IIci;
-
-        /* initialize the hardwired (primary, autovector) IRQs */
-
-	/* level 1 IRQ: VIA1, always present */
-	sys_request_irq(1, via1_irq, IRQ_FLG_LOCK, "via1", via1_irq);
-
-	/* via2 or rbv?? */
-	if (macintosh_config->via_type == MAC_VIA_IIci) {
-		/*
-		 * A word of caution: the definitions here only affect interrupt
-		 * handling, see via6522.c for yet another file to change
-		 * base addresses and RBV flags
-		 */
-
-		/* yes, this is messy - the IIfx deserves a class of his own */
-		if (macintosh_config->ident == MAC_MODEL_IIFX) {
-			/* no real VIA2, the OSS seems _very_ different */	
-			via2_is_oss = 1;
-			/* IIfx has OSS, at a different base address than RBV */
-			rbv_regp = (unsigned char *) OSS_BAS;
-			sys_request_irq(2, oss_irq, IRQ_FLG_LOCK, "oss", oss_irq);
-		} else {
-			/* VIA2 is part of the RBV: different base, other offsets */
-			via2_is_rbv = 1;
-
-			/* LC III weirdness: IFR seems to behave like VIA2 */
-			/* FIXME: maybe also for LC II ?? */ 
-			if (macintosh_config->ident == MAC_MODEL_LCIII) {
-				rbv_clear = 0x0;
-			} else {
-				rbv_clear = 0x80;
-			}
-			/* level 2 IRQ: RBV/OSS; we only care about RBV for now */
-			sys_request_irq(2, rbv_irq, IRQ_FLG_LOCK, "rbv", rbv_irq);
-		}
-	} else
-		/* level 2 IRQ: VIA2 */
-		sys_request_irq(2, via2_irq, IRQ_FLG_LOCK, "via2", via2_irq);
-
 	/* 
-	 * level 4 IRQ: SCC - use 'master' interrupt routine that calls the 
-	 *		registered channel-specific interrupts in turn.
-	 *		Currently, one interrupt per channel is used, solely
-	 *		to pass the correct async_info as parameter!
+	 * Register the handlers for the the master IRQ handlers
+	 * at levels 1-7. Most of the work is done elsewhere.
 	 */
 
-	sys_request_irq(4, mac_debug_handler, IRQ_FLG_STD, "INT4", mac_debug_handler);
-
-	/* level 6 */
-	sys_request_irq(6, mac_bang, IRQ_FLG_LOCK, "offswitch", mac_bang);
-
-	/* level 7 (or NMI) : debug stuff */
-	sys_request_irq(7, mac_nmi_handler, IRQ_FLG_STD, "NMI", mac_nmi_handler);
-
-	/* initialize the handler tables for VIAs */
-	for (i = 0; i < 8; i++) {
-		via1_handler[i].handler = mac_default_handler;
-		via1_handler[i].dev_id  = NULL;
-		via1_param[i].flags     = IRQ_FLG_STD;
-		via1_param[i].devname   = NULL;
-
-		via2_handler[i].handler = mac_default_handler;
-		via2_handler[i].dev_id  = NULL;
-		via2_param[i].flags     = IRQ_FLG_STD;
-		via2_param[i].devname   = NULL;
-
-		rbv_handler[i].handler = mac_default_handler;
-		rbv_handler[i].dev_id  = NULL;
-		rbv_param[i].flags     = IRQ_FLG_STD;
-		rbv_param[i].devname   = NULL;
-
-		scc_handler[i].handler = mac_default_handler;
-		scc_handler[i].dev_id  = NULL;
-		scc_param[i].flags     = IRQ_FLG_STD;
-		scc_param[i].devname   = NULL;
-
-		/* NUBUS interrupts routed through VIA2 slot 2 - special */
-		nubus_handler[i].handler = nubus_wtf;
-		nubus_handler[i].dev_id  = NULL;
-		nubus_param[i].flags     = IRQ_FLG_STD;
-		nubus_param[i].devname   = NULL;
-
-	}
-
-	/* initialize the handler tables (level 1 -> via_handler[0] !!!) */
-	via_table[0]     =  via1_regp;
-	handler_table[0] =  &via1_handler[0];
-	param_table[0]   =  &via1_param[0];
-	mac_irqs[0]	 =  &via1_irqs[0];
-
-	if (via2_is_rbv || via2_is_oss) {
-		via_table[1]     =  rbv_regp;
-		handler_table[1] =  &rbv_handler[0];
-		param_table[1]   =  &rbv_param[0];
-		mac_irqs[1]	 =  &rbv_irqs[0];
+	if (oss_present) {
+		oss_register_interrupts();
 	} else {
-		via_table[1]     =  via2_regp;
-		handler_table[1] =  &via2_handler[0];
-		param_table[1]   =  &via2_param[0];
-		mac_irqs[1]	 =  &via2_irqs[0];
-	}
-	via_table[2]     =  NULL;
-	via_table[3]     =  NULL;
-	
-	handler_table[2] =  &rbv_handler[0];
-	handler_table[3] =  &scc_handler[0];
-	handler_table[4] =  NULL;
-	handler_table[5] =  NULL;
-	handler_table[6] =  NULL;
-	handler_table[7] =  &nubus_handler[0];
-
-	param_table[2]   =  &rbv_param[0];
-	param_table[3]   =  &scc_param[0];
-	param_table[7]   =  &nubus_param[0];
-
-	mac_irqs[2]	 =  &rbv_irqs[0];
-	mac_irqs[3]	 =  &scc_irqs[0];
-	mac_irqs[7]	 =  &nubus_irqs[0];
-
-	/*
-	 * Nubus Macs: turn off the Nubus dispatch interrupt for now
-	 */
-
-	mac_turnoff_irq(IRQ_MAC_NUBUS);
-
-	/*
-	 *	AV Macs: shutup the PSC ints
-	 */
-	if (macintosh_config->ident == MAC_MODEL_C660
-	 || macintosh_config->ident == MAC_MODEL_Q840) 
-	{
-		psc_init();
-
-		handler_table[2] = &psc3_handler[0];
-		/* handler_table[3] = &psc4_handler[0]; */
-		handler_table[4] = &psc5_handler[0];
-		handler_table[5] = &psc6_handler[0];
-
-		param_table[2]   = &psc3_param[0];
-		/* param_table[3]   = &psc4_param[0]; */
-		param_table[4]   = &psc5_param[0];
-		param_table[5]   = &psc6_param[0];
-
-		mac_irqs[2]	 = &psc3_irqs[0]; 
-		/* mac_irqs[3]	 = &psc4_irqs[0]; */
-		mac_irqs[4]	 = &psc5_irqs[0];
-		mac_irqs[5]	 = &psc6_irqs[0];
-
-		sys_request_irq(3, psc_irq, IRQ_FLG_STD, "PSC3", psc_irq);
-		sys_request_irq(4, psc_irq, IRQ_FLG_STD, "PSC4", psc_irq);
-		sys_request_irq(5, psc_irq, IRQ_FLG_STD, "PSC5", psc_irq);
-		sys_request_irq(6, psc_irq, IRQ_FLG_STD, "PSC6", psc_irq);
+		via_register_interrupts();
 	}
-
+	if (psc_present) psc_register_interrupts();
+	iop_register_interrupts();
+	request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler);
 #ifdef DEBUG_MACINTS
-	printk("Mac interrupt init done!\n");
+	printk("mac_init_IRQ(): Done!\n");
 #endif
 }
 
 /*
- *	We have no machine specific interrupts on a macintoy
- *      Yet, we need to register/unregister interrupts ... :-)
- *      Currently unimplemented: Test for valid irq number, chained irqs,
- *      Nubus interrupts (use nubus_request_irq!).
+ * Routines to work with irq_node_t's on linked lists lifted from
+ * the Amiga code written by Roman Zippel.
  */
- 
-int mac_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-                              unsigned long flags, const char *devname, void *dev_id)
-{
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx =  (irq & IRQ_IDX_MASK);
-	struct irqhandler *via_handler;
-	struct irqparam   *via_param;
-	volatile unsigned char *via;
-
-#ifdef DEBUG_MACINTS
-	printk ("%s: IRQ %d on VIA%d[%d] requested from %s\n",
-	        __FUNCTION__, irq, srcidx+1, irqidx, devname);
-#endif
-
-	if (flags < IRQ_TYPE_SLOW || flags > IRQ_TYPE_PRIO) {
-		printk ("%s: Bad irq type %ld requested from %s\n",
-		        __FUNCTION__, flags, devname);
-		return -EINVAL;
-	}
-
-	/* figure out what VIA is handling this irq */
-        if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) {
-		/* non-via irqs unimplemented */
-		printk ("%s: Bad irq source %d on VIA %d requested from %s\n",
-		        __FUNCTION__, irq, srcidx, devname);
-		return -EINVAL;
-	} 
-
-	/* figure out if SCC pseudo-irq (redundant ??) */
-        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
-		/* set specific SCC handler */
-		scc_handler[irqidx].handler = handler;
-		scc_handler[irqidx].dev_id  = dev_id;
-		scc_param[irqidx].flags     = flags;
-		scc_param[irqidx].devname   = devname;
-		/* and done! */
-		return 0;
-	} 
-
-	/* 
-	 * code below: only for VIA irqs currently 
-	 * add similar hack for Nubus pseudo-irq here - hide nubus_request_irq
-	 */
-	via         = (volatile unsigned char *) via_table[srcidx];
-	if (!via) 
-		return -EINVAL;
-
-	via_handler = handler_table[srcidx];
-	via_param   = param_table[srcidx];
-
-	/* check for conflicts or possible replacement */
-
-	/* set the handler - no chained irqs yet !! */
-	via_handler[irqidx].handler = handler;
-	via_handler[irqidx].dev_id  = dev_id;
-	via_param[irqidx].flags     = flags;
-	via_param[irqidx].devname   = devname;
-
-	/* and turn it on ... careful, that's VIA only ... */
-	if (srcidx == SRC_VIA2 && via2_is_rbv)
-		via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
-	else if (srcidx == SRC_VIA2 && via2_is_oss)
-		via_write(oss_regp, oss_map[irqidx]+8, 2);
-	else
-		via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
-
-
-	if (irq == IRQ_IDX(IRQ_MAC_SCSI)) {
-		/*
-		 * Set vPCR for SCSI interrupts. (what about RBV here?)
-		 * 980429 MS: RBV is ok, OSS seems to be different
-		 */
-		if (!via2_is_oss)
-			if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
-				/* CB2 (IRQ) indep. interrupt input, positive edge */
-				/* CA2 (DRQ) indep. interrupt input, positive edge */
-				via_write(via, vPCR, 0x66);
-			} else {
-				/* CB2 (IRQ) indep. interrupt input, negative edge */
-				/* CA2 (DRQ) indep. interrupt input, negative edge */
-				via_write(via, vPCR, 0x22);
-			}
-#if 0
-		else
-			/* CB2 (IRQ) indep. interrupt input, negative edge */
-			/* CA2 (DRQ) indep. interrupt input, negative edge */
-			via_write(via, vPCR, 0x22);
-#endif
-	}
 
-	return 0;
-}
-                            
-void mac_free_irq (unsigned int irq, void *dev_id)
+static inline void mac_insert_irq(irq_node_t **list, irq_node_t *node)
 {
-	unsigned long flags;
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx =  (irq & IRQ_IDX_MASK);
-	struct irqhandler *via_handler;
-	struct irqparam   *via_param;
-	volatile unsigned char *via;
+	unsigned long cpu_flags;
+	irq_node_t *cur;
 
-#ifdef DEBUG_MACINTS
-	printk ("%s: IRQ %d on VIA%d[%d] freed\n",
-	        __FUNCTION__, irq, srcidx+1, irqidx);
-#endif
+	if (!node->dev_id)
+		printk("%s: Warning: dev_id of %s is zero\n",
+		       __FUNCTION__, node->devname);
 
-	/* figure out what VIA is handling this irq */
-	if (irq < IRQ_IDX(IRQ_VIA1_1) || irq >= IRQ_IDX(IRQ_NUBUS_1)) {
-		/* non-via irqs unimplemented */
-		return;
-	} 
-
-	save_flags(flags);
+	save_flags(cpu_flags);
 	cli();
 
-	/* figure out if SCC pseudo-irq */
-        if (irq >= IRQ_IDX(IRQ_SCC) && irq < IRQ_IDX(IRQ_PSC5_0)) {
-		/* clear specific SCC handler */
-		scc_handler[irqidx].handler = mac_default_handler;
-		scc_handler[irqidx].dev_id  = NULL;
-		scc_param[irqidx].flags     = IRQ_FLG_STD;
-		scc_param[irqidx].devname   = NULL;
-		/* and done! */
-		restore_flags(flags);
-		return;
-	} 
+	cur = *list;
 
-	via         = (volatile unsigned char *) via_table[srcidx];
-	via_handler = handler_table[srcidx];
-	via_param   = param_table[srcidx];
-
-	if ( !via || (via_handler[irqidx].dev_id != dev_id) ) {
-		restore_flags(flags);
-		goto not_found;
+	if (node->flags & IRQ_FLG_FAST) {
+		node->flags &= ~IRQ_FLG_SLOW;
+		while (cur && cur->flags & IRQ_FLG_FAST) {
+			list = &cur->next;
+			cur = cur->next;
+		}
+	} else if (node->flags & IRQ_FLG_SLOW) {
+		while (cur) {
+			list = &cur->next;
+			cur = cur->next;
+		}
+	} else {
+		while (cur && !(cur->flags & IRQ_FLG_SLOW)) {
+			list = &cur->next;
+			cur = cur->next;
+		}
 	}
 
-	/* clear the handler - no chained irqs yet !! */
-	via_handler[irqidx].handler = mac_default_handler;
-	via_handler[irqidx].dev_id  = NULL;
-	via_param[irqidx].flags     = IRQ_FLG_STD;
-	via_param[irqidx].devname   = NULL;
-
-	/* and turn it off */
-	if (srcidx == SRC_VIA2 && via2_is_rbv)
-		via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
-	else if (srcidx == SRC_VIA2 && via2_is_oss)
-		via_write(oss_regp, oss_map[irqidx]+8, 0);
-	else
-		via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
-
-	restore_flags(flags);
-	return;
-
-not_found:
-	printk("%s: tried to remove invalid irq\n", __FUNCTION__);
-	return;
+	node->next = cur;
+	*list = node;
 
+	restore_flags(cpu_flags);
 }
 
-/*
- * {en,dis}able_irq have the usual semantics of temporary blocking the
- * interrupt, but not loosing requests that happen between disabling and
- * enabling. On Atari, this is done with the MFP mask registers.
- *
- * On the Mac, this isn't possible: there is no VIA mask register. 
- * Needs to be implemented in software, setting 'mask' bits in a separate
- * struct for each interrupt controller. These mask bits need to be checked
- * by the VIA interrupt routine which should ignore requests for masked IRQs 
- * (after possibly ack'ing them).
- *
- * On second thought: some of the IRQ sources _can_ be turned off via bits
- * in the VIA output registers. Need to check this ...
- *
- * TBI: According to the VIA docs, clearing a bit in the IER has the effect of 
- * blocking generation of the interrupt, but the internal interrupt condition 
- * is preserved. So the IER might be used as mask register here, and turnon_irq
- * would need to clear the interrupt bit in the IFR to prevent getting an 
- * interrupt at all.
- *
- * Implementation note: the irq no's here are the _machspec_ irqs, hence the 
- * hack with srcidx to figure out which VIA/RBV handles the interrupt. 
- * That's fundamentally different when it comes to the interrupt handlers 
- * proper: these get the interrupt level no. as argument, all information about
- * which source triggered the int. is buried in the VIA IFR ... The int. level 
- * points us to the proper handler, so we could do a sanity check there ...
- */
-
-void mac_enable_irq (unsigned int irq)
+static inline void mac_delete_irq(irq_node_t **list, void *dev_id)
 {
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx = (irq & IRQ_IDX_MASK);
+	unsigned long cpu_flags;
+	irq_node_t *node;
 
-	irq_flags[srcidx].disabled &= ~(1<<irqidx);
-	/*
-	 * Call handler here if irq_flags[srcidx].pending & 1<<irqidx ?? 
-	 * The structure of via_irq prevents this, sort of: it warns if
-	 * no true events are pending. Maybe that's being changed ...
-	 * Other problem: is it always possible to call an interrupt handler, 
-	 * or should that depend on the current interrupt level?
-	 */
-}
-
-void mac_disable_irq (unsigned int irq)
-{
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx = (irq & IRQ_IDX_MASK);
+	save_flags(cpu_flags);
+	cli();
 
-	irq_flags[srcidx].disabled |= (1<<irqidx);
+	for (node = *list; node; list = &node->next, node = *list) {
+		if (node->dev_id == dev_id) {
+			*list = node->next;
+			/* Mark it as free. */
+			node->handler = NULL;
+			restore_flags(cpu_flags);
+			return;
+		}
+	}
+	restore_flags(cpu_flags);
+	printk ("%s: tried to remove invalid irq\n", __FUNCTION__);
 }
 
 /*
- * In opposite to {en,dis}able_irq, requests between turn{off,on}_irq are not
- * "stored". This is done with the VIA interrupt enable register on VIAs.
+ * Call all the handlers for a given interrupt. Fast handlers are called
+ * first followed by slow handlers.
  *
- * Note: Using these functions on non-VIA/OSS/PSC ints will panic, or at least 
- * have undesired side effects.
+ * This code taken from the original Amiga code written by Roman Zippel.
  */
 
-void mac_turnon_irq( unsigned int irq )
+void mac_do_irq_list(int irq, struct pt_regs *fp)
 {
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx = (irq & IRQ_IDX_MASK);
-	volatile unsigned char *via;
-
-	via         = (volatile unsigned char *) via_table[srcidx];
-	if (!via) 
-		return;
+	irq_node_t *node, *slow_nodes, **list = NULL;
+	unsigned long cpu_flags;
 
-	if (srcidx == SRC_VIA2 && via2_is_rbv)		/* RBV as VIA2 */
-	        via_write(via, rIER, via_read(via, rIER)|0x80|(1<<(irqidx)));
-	else if (srcidx == SRC_VIA2 && via2_is_oss)	/* OSS */
-		via_write(oss_regp, oss_map[irqidx]+8, 2);
-	else if (srcidx > SRC_VIA2)			/* hope AVs have VIA2 */
-	        via_write(via, (0x104 + 0x10*srcidx), 
-	        	via_read(via, (0x104 + 0x10*srcidx))|0x80|(1<<(irqidx)));
-	else						/* VIA1+2 */
-	        via_write(via, vIER, via_read(via, vIER)|0x80|(1<<(irqidx)));
+	kstat.irqs[0][irq]++;
 
-}
-
-void mac_turnoff_irq( unsigned int irq )
-{
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx = (irq & IRQ_IDX_MASK);
-	volatile unsigned char *via;
+	if (irq < VIA1_SOURCE_BASE) {
+		list = &autoirq_list[irq];
+	} else if (irq < NUM_MAC_SOURCES) {
+		list = &userirq_list[irq - VIA1_SOURCE_BASE];
+	}
+	if (!list) return;
 
-	via         = (volatile unsigned char *) via_table[srcidx];
-	if (!via) 
+#ifdef DEBUG_SPURIOUS
+	if (!*list && (console_loglevel > 7)) {
+		printk("mac_do_irq_list: spurious interrupt %d!\n", irq);
 		return;
+	}
+#endif
 
-	if (srcidx == SRC_VIA2 && via2_is_rbv)		/* RBV as VIA2 */
-		via_write(via, rIER, (via_read(via, rIER)&(1<<irqidx)));
-	else if (srcidx == SRC_VIA2 && via2_is_oss)	/* OSS */
-		via_write(oss_regp, oss_map[irqidx]+8, 0);
-	/*
-	 *	VIA2 is fixed. The stuff above VIA2 is for later
-	 *	macintoshes only.
-	 */
-	else if (srcidx > SRC_VIA2)
-	        via_write(via, (0x104 + 0x10*srcidx), 
-	        	via_read(via, (0x104 + 0x10*srcidx))|(1<<(irqidx)));
-	else						/* VIA1+2 */
-		via_write(via, vIER, (via_read(via, vIER)&(1<<irqidx)));
+	/* serve first fast and normal handlers */
+	for (node = *list;
+	     node && (!(node->flags & IRQ_FLG_SLOW));
+	     node = node->next)
+		node->handler(irq, node->dev_id, fp);
+	if (!node) return;
+	save_flags(cpu_flags);
+	restore_flags((cpu_flags & ~0x0700) | (fp->sr & 0x0700));
+	/* if slow handlers exists, serve them now */
+	slow_nodes = node;
+	for (; node; node = node->next) {
+		node->handler(irq, node->dev_id, fp);
+	}
 }
 
 /*
- * These functions currently only handle the software-maintained irq pending
- * list for disabled irqs - manipulating the actual irq flags in the via would
- * require clearing single bits in the via, such as (probably) 
- * via_write(via, vIFR, (via_read(via, vIFR)&(1<<irqidx))); - don't know if 
- * this has side-effects ...
+ *  mac_enable_irq - enable an interrupt source
+ * mac_disable_irq - disable an interrupt source
+ *   mac_clear_irq - clears a pending interrupt
+ * mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)
+ *
+ * These routines are just dispatchers to the VIA/OSS/PSC routines.
  */
 
-void mac_clear_pending_irq( unsigned int irq )
+void mac_enable_irq (unsigned int irq)
 {
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx = (irq & IRQ_IDX_MASK);
-
-	irq_flags[srcidx].pending &= ~(1<<irqidx);
+	switch(IRQ_SRC(irq)) {
+		case 1: via_irq_enable(irq);
+			break;
+		case 2:
+		case 7: if (oss_present) {
+				oss_irq_enable(irq);
+			} else {
+				via_irq_enable(irq);
+			}
+			break;
+		case 3:
+		case 4:
+		case 5:
+		case 6: if (psc_present) {
+				psc_irq_enable(irq);
+			} else if (oss_present) {
+				oss_irq_enable(irq);
+			}
+			break;
+	}
 }
 
-int  mac_irq_pending( unsigned int irq )
+void mac_disable_irq (unsigned int irq)
 {
-	int pending = 0;
-	volatile unsigned char *via;
-
-	int srcidx = ((irq & IRQ_SRC_MASK)>>3) - 1;
-	int irqidx = (irq & IRQ_IDX_MASK);
-
-	pending = irq_flags[srcidx].pending & (1<<irqidx);
+	switch(IRQ_SRC(irq)) {
+		case 1: via_irq_disable(irq);
+			break;
+		case 2:
+		case 7:
+			if (oss_present) {
+				oss_irq_disable(irq);
+			} else {
+				via_irq_disable(irq);
+			}
+			break;
+		case 3:
+		case 4:
+		case 5:
+		case 6: if (psc_present) {
+				psc_irq_disable(irq);
+			} else if (oss_present) {
+				oss_irq_disable(irq);
+			}
+			break;
+	}
+}
 
-	via         = (volatile unsigned char *) via_table[srcidx];
-	if (!via) 
-		return (pending);
-
-	if (srcidx == SRC_VIA2 && via2_is_rbv)
-		pending |= via_read(via, rIFR)&(1<<irqidx);
-	else if (srcidx == SRC_VIA2 && via2_is_oss)
-		pending |= via_read(via, oIFR)&0x03&(1<<oss_map[irqidx]);
-	else if (srcidx > SRC_VIA2)
-	        pending |= via_read(via, (0x100 + 0x10*srcidx))&(1<<irqidx);
-	else
-		pending |= via_read(via, vIFR)&(1<<irqidx);
+void mac_clear_irq( unsigned int irq )
+{
+	switch(IRQ_SRC(irq)) {
+		case 1: via_irq_clear(irq);
+			break;
+		case 2:
+		case 7: if (oss_present) {
+				oss_irq_clear(irq);
+			} else {
+				via_irq_clear(irq);
+			}
+			break;
+		case 3:
+		case 4:
+		case 5:
+		case 6: if (psc_present) {
+				psc_irq_clear(irq);
+			} else if (oss_present) {
+				oss_irq_clear(irq);
+			}
+			break;
+	}
+}
 
-	return (pending);
+int mac_irq_pending( unsigned int irq )
+{
+	switch(IRQ_SRC(irq)) {
+		case 1: return via_irq_pending(irq);
+		case 2:
+		case 7: if (oss_present) {
+				return oss_irq_pending(irq);
+			} else {
+				return via_irq_pending(irq);
+			}
+		case 3:
+		case 4:
+		case 5:
+		case 6: if (psc_present) {
+				return psc_irq_pending(irq);
+			} else if (oss_present) {
+				return oss_irq_pending(irq);
+			}
+	}
+	return 0;
 }
 
 /*
- * for /proc/interrupts: log interrupt stats broken down by 
- * autovector int first, then by actual interrupt source.
+ * Add an interrupt service routine to an interrupt source.
+ * Returns 0 on success.
+ *
+ * FIXME: You can register interrupts on nonexistant source (ie PSC4 on a
+ *        non-PSC machine). We should return -EINVAL in those cases.
  */
-
-int mac_get_irq_list (char *buf)
+ 
+int mac_request_irq(unsigned int irq,
+		    void (*handler)(int, void *, struct pt_regs *),
+		    unsigned long flags, const char *devname, void *dev_id)
 {
-	int i, len = 0;
-	int srcidx, irqidx;
+	int vec, ret;
 
-	for (i = VIA1_SOURCE_BASE; i < NUM_MAC_SOURCES+8; ++i) {
-	        /* XXX fixme: IRQ_SRC_MASK should cover VIA1 - Nubus */
-		srcidx = ((i & IRQ_SRC_MASK)>>3) - 1;
-		irqidx = (i & IRQ_IDX_MASK);
-
-		/*
-		 * Not present: skip
-		 */
-
-		if (mac_irqs[srcidx] == NULL)
-			continue;
-
-		/* 
-		 * never used by VIAs, unused by others so far, counts 
-		 * the magic 'nothing pending' cases ...
-		 */
-		if (irqidx == 7 && mac_irqs[srcidx][irqidx]) {
-			len += sprintf(buf+len, "Level %01d: %10lu (spurious) \n",
-				       srcidx, 
-				       mac_irqs[srcidx][irqidx]);
-			continue;
-		}
-
-		/*
-		 * Nothing registered for this IPL: skip
-		 */
-
-		if (handler_table[srcidx] == NULL)
-			continue;
-
-		/*
-		 * No handler installed: skip
-		 */ 
-
-		if (handler_table[srcidx][irqidx].handler == mac_default_handler ||
-		    handler_table[srcidx][irqidx].handler == nubus_wtf)
-			continue;
-
-
-		if (i < VIA2_SOURCE_BASE)
-			len += sprintf(buf+len, "via1  %01d: %10lu ",
-				       irqidx,
-				       mac_irqs[srcidx][irqidx]);
-		else if (i < RBV_SOURCE_BASE)
-			len += sprintf(buf+len, "via2  %01d: %10lu ",
-				       irqidx,
-				       mac_irqs[srcidx][irqidx]);
-		else if (i < MAC_SCC_SOURCE_BASE)
-			len += sprintf(buf+len, "rbv   %01d: %10lu ",
-				       irqidx,
-				       mac_irqs[srcidx][irqidx]);
-		else if (i < NUBUS_SOURCE_BASE)
-			len += sprintf(buf+len, "scc   %01d: %10lu ",
-				       irqidx,
-				       mac_irqs[srcidx][irqidx]);
-		else /* Nubus */
-			len += sprintf(buf+len, "nubus %01d: %10lu ",
-				       irqidx,
-				       mac_irqs[srcidx][irqidx]);
-
-			len += sprintf(buf+len, "%s\n", 
-				       param_table[srcidx][irqidx].devname);
+#ifdef DEBUG_MACINTS
+	printk ("%s: irq %d requested for %s\n", __FUNCTION__, irq, devname);
+#endif
 
+	if (irq < VIA1_SOURCE_BASE) {
+		vec = VEC_SPUR + irq;
+	} else if (irq < NUM_MAC_SOURCES) {
+		vec = VEC_USER + irq - VIA1_SOURCE_BASE;
+	} else {
+		printk ("%s: unknown irq %d requested by %s\n",
+		        __FUNCTION__, irq, devname);
+		return -EAGAIN;
 	}
-	if (num_spurious)
-		len += sprintf(buf+len, "spurio.: %10u\n", num_spurious);
-
-	/* 
-	 * XXX Fixme: Nubus sources are never logged above ...
-	 */
-
-	len += sprintf(buf+len, "Nubus interrupts:\n");
-
-	for (i = 0; i < 7; i++) {
-		if (nubus_handler[i].handler == nubus_wtf)
-			continue;
-		len += sprintf(buf+len, "nubus %01X: %10lu ",
-			       i+9, 
-			       nubus_irqs[i]);
-		len += sprintf(buf+len, "%s\n", 
-			       nubus_param[i].devname);
 
+	ret = sys_request_listirq(vec, handler, flags, devname, dev_id);
+	if (!ret) {
+		vectors[vec] = autoirq_listhandler;
+		mac_enable_irq(irq);
 	}
-	len += sprintf(buf+len, "nubus spurious ints: %10lu\n",
-		       nubus_irqs[7]);
-	len += sprintf(buf+len, "nubus stuck events : %10lu\n",
-		       nubus_stuck_events);
-#ifdef CONFIG_BLK_DEV_IDE
-	len += sprintf(buf+len, "nubus/IDE interrupt: %10lu\n",
-		       mac_ide_irqs);
-#endif	
 
-	return len;
+	return ret;
 }
+                            
+/*
+ * Removes an interrupt service routine from an interrupt source.
+ */
 
-void via_scsi_clear(void)
+void mac_free_irq(unsigned int irq, void *dev_id)
 {
-	volatile unsigned char deep_magic;
-	if (via2_is_rbv) {
-		via_write(rbv_regp, rIFR, (1<<3)|(1<<0)|0x80);
-		deep_magic = via_read(rbv_regp, rBufB);
-	} else if (via2_is_oss) {
-		/* nothing */
-		/* via_write(oss_regp, 9, 0) */;
-	} else
-		deep_magic = via_read(via2_regp, vBufB);
-	mac_enable_irq( IRQ_IDX(IRQ_MAC_SCSI) );
-}
+	irq_node_t **list = NULL;
+	int vec = 0;
 
-
-void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
-	if (console_loglevel > 6)
-		printk("Unexpected IRQ %d on device %p\n", irq, dev_id);
+#ifdef DEBUG_MACINTS
+	printk ("%s: irq %d freed by %p\n", __FUNCTION__, irq, dev_id);
 #endif
-}
 
-static int num_debug[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+	if (irq < VIA1_SOURCE_BASE) {
+		vec = VEC_SPUR + irq;
+		list = &autoirq_list[irq];
+	} else if (irq < NUM_MAC_SOURCES) {
+		vec = VEC_USER + irq - VIA1_SOURCE_BASE;
+		list = &userirq_list[irq - VIA1_SOURCE_BASE];
+	}
+	if (!list) return;
 
-void mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-	if (num_debug[irq] < 10) {
-		printk("DEBUG: Unexpected IRQ %d\n", irq);
-		num_debug[irq]++;
+	sys_free_irq(vec, dev_id);
+
+	/* If the list for this interrupt is */
+	/* empty then disable the source.    */
+
+	if (!*list) {
+		mac_disable_irq(irq);
+		vectors[vec] = bad_interrupt;
 	}
 }
 
-void scsi_mac_debug(void);
-void scsi_mac_polled(void);
-
 static int in_nmi = 0;
 static volatile int nmi_hold = 0;
 
@@ -869,10 +505,6 @@
 	 */
 
 	in_nmi++;
-#if 0
-	scsi_mac_debug();
-	printk("PC: %08lx\nSR: %04x  SP: %p\n", fp->pc, fp->sr, fp);
-#endif
 	for (i=0; i<100; i++)
 		udelay(1000);
 
@@ -889,10 +521,6 @@
 	while (nmi_hold == 1)
 		udelay(1000);
 
-#if 0
-	scsi_mac_polled();
-#endif
-
 	if ( console_loglevel >= 8 ) {
 #if 0
 		show_state();
@@ -916,799 +544,12 @@
 }
 
 /*
- *	Unexpected via interrupt
- */
- 
-void via_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_SPURIOUS
-	if (console_loglevel > 6)
-		printk("Unexpected nubus event %d on via %p\n",slot,via);
-#endif
-}
-
-/*
- * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
- * via6522.c :-), disable/pending masks added.
- * The int *viaidx etc. is just to keep the prototype happy ...
- */
-
-static void via_irq(unsigned char *via, int *viaidx, struct pt_regs *regs)
-{
-	unsigned char events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
-	int i;
-	int ct = 0;
-	struct irqhandler *via_handler = handler_table[*viaidx];
-	struct irqparam   *via_param   = param_table[*viaidx];
-	unsigned long     *via_irqs    = mac_irqs[*viaidx];
-
-	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
-	 * flag bit, ack and call handler ...
-         * Currently: all pending irqs ack'ed en bloc.
-	 * If ack for masked IRQ required: keep 'pending' info separate.
-	 */
-
-        /* shouldn't we disable interrupts here ?? */
-
-	
-	/*
-	 *	Shouldnt happen
-	 */
-	 
-	if(events==0)
-	{
-#ifdef DEBUG_VIA
-		/* should go away; mostly missing timer ticks and ADB events */
-		printk("via%d_irq: nothing pending, flags %x mask %x!\n",
-			*viaidx + 1, via_read(via, vIFR), via_read(via,vIER));
-#endif
-		via_irqs[7]++;
-		return;
-	}
-
-#ifdef DEBUG_VIA	
-	/*
-	 * limited verbosity for VIA interrupts
-	 */
-#if 0
-	if ( (*viaidx == 0 && events != 1<<6) 		/* timer int */
-	  || (*viaidx == 1 && events != 1<<3) )		/* SCSI IRQ */
-#else
-	if ( *viaidx == 0 && (events & 1<<2) ) 
-#endif
-		printk("via_irq: irq %d events %x !\n", (*viaidx)+1, events);
-#endif
-
-	do {
-		/*
-		 *	Clear the pending flag
-		 */
-		 
-		via_write(via, vIFR, events);
-		 
-		/*
-		 *	Now see what bits are raised
-		 */
-		 
-		for(i=0;i<7;i++)
-		{
-			/* determine machspec. irq no. */
-			int irq = ((*viaidx)+1)* 8 + i;
-		        /* call corresponding handlers */
-		        if (events&(1<<i)) {
-			        if (irq_flags[*viaidx].disabled & (1<<i)) {
-					if (!irq_flags[*viaidx].pending&(1<<i))
-						via_irqs[i]++;
-				        /* irq disabled -> mark pending */
-				        irq_flags[*viaidx].pending |= (1<<i);
-				} else {
-					via_irqs[i]++;
-				        /* irq enabled -> call handler */
-				        (via_handler[i].handler)(irq, via, regs);
-				}
-			}
-			/* and call handlers for pending irqs - first ?? */
-			if (    (irq_flags[*viaidx].pending  & (1<<i))
-			    && !(irq_flags[*viaidx].disabled & (1<<i)) ) {
-				/* call handler for re-enabled irq */
-			        (via_handler[i].handler)(irq, via, regs);
-				/* and clear pending flag :-) */
-				irq_flags[*viaidx].pending  &= ~(1<<i);
-			}
-		}
-	
-		/*
-		 *	And done ... check for more punishment!
-		 */
-
-		events=(via_read(via, vIFR)&via_read(via,vIER))&0x7F;
-		ct++;
-		if(events && ct>8)
-		{
-#ifdef DEBUG_VIA
-		        printk("via%d: stuck events %x\n", (*viaidx)+1, events);
-#endif
-		        break;
-		}
-	}
-	while(events);
-#if 0
-	scsi_mac_polled();
-#endif
-}
-
-/*
- * Caution: the following stuff is called from process_int as _autovector_ 
- * system interrupts. So irq is always in the range 0-7 :-( and the selection
- * of the appropriate VIA is up to the irq handler here based on the autovec 
- * irq number. There's no information whatsoever about which source on the VIA
- * triggered the int - and that's what the machspec irq no's are about. 
- * Broken design :-((((
- */
-
-/*
- *	System interrupts
- */
-
-void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int srcidx = IRQ_IDX(irq) - 1;
-	via_irq((unsigned char *)via1_regp, &srcidx, regs);
-}
-
-
-/*
- *	Nubus / SCSI interrupts, VIA style (could be wrapped into via1_irq or
- *	via_irq directly by selecting the regp based on the irq!)
- */
- 
-void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int srcidx = IRQ_IDX(irq) - 1;
-	via_irq((unsigned char *)via2_regp, &srcidx, regs);
-}
-
-/*
- *	Nubus / SCSI interrupts; RBV style
- *	The RBV is different. RBV appears to stand for randomly broken
- *	VIA (or even real broken VIA).
- */
- 
-void rbv_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int srcidx = IRQ_IDX(irq) - 1;	/* MUST be 1 !! */
-	volatile unsigned char *via = rbv_regp;
-	unsigned char events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
-	int i;
-	int ct = 0;
-	struct irqhandler *via_handler = handler_table[srcidx];
-	struct irqparam   *via_param   = param_table[srcidx];
-
-        /* shouldn't we disable interrupts here ?? */
-
-	
-	/*
-	 *	Shouldnt happen
-	 */
-	 
-	if(events==0)
-	{
-#ifdef DEBUG_VIA
-		printk("rbv_irq: nothing pending, flags %x mask %x!\n",
-			via_read(via, rIFR), via_read(via,rIER));
-#endif
-		rbv_irqs[7]++;
-		return;
-	}
-
-#ifdef DEBUG_VIA	
-	/*
-	 * limited verbosity for RBV interrupts (add more if needed)
-	 */
-	if ( srcidx == 1 && events != 1<<3 )		/* SCSI IRQ */
-		printk("rbv_irq: irq %d (%d) events %x !\n", irq, srcidx+1, events);
-#endif
-
-	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
-	 * flag bit, ack and call handler ...
-         * Currently: all pending irqs ack'ed en bloc.
-	 * If ack for masked IRQ required: keep 'pending' info separate.
-	 */
-
-	do {
-		/*
-		 *	Clear the pending flag
-		 */
-		 
-		via_write(via, rIFR, events | rbv_clear);
-		 
-		/*
-		 *	Now see what bits are raised
-		 */
-		 
-		for(i=0;i<7;i++)
-		{
-			/* determine machspec. irq no. */
-			int irq = (srcidx+1)* 8 + i;
-		        /* call corresponding handlers */
-		        if (events&(1<<i)) {
-			        if (irq_flags[srcidx].disabled & (1<<i)) {
-					if (!irq_flags[srcidx].pending&(1<<i))
-						rbv_irqs[i]++;
-				        /* irq disabled -> mark pending */
-				        irq_flags[srcidx].pending |= (1<<i);
-				} else {
-					rbv_irqs[i]++;
-				        /* irq enabled -> call handler */
-				        (via_handler[i].handler)(irq, via, regs);
-				}
-			}
-			/* and call handlers for pending irqs - first ?? */
-			if (    (irq_flags[srcidx].pending  & (1<<i))
-			    && !(irq_flags[srcidx].disabled & (1<<i)) ) {
-				/* call handler for re-enabled irq */
-			        (via_handler[i].handler)(irq, via, regs);
-				/* and clear pending flag :-) */
-				irq_flags[srcidx].pending  &= ~(1<<i);
-			}
-		}
-
-		/*
-		 *	And done ... check for more punishment!
-		 */
-
-		events=(via_read(via, rIFR)&via_read(via,rIER))&0x7F;
-		ct++;
-		if(events && ct>8)
-		{
-		        printk("rbv: stuck events %x\n",events);
-			for(i=0;i<7;i++)
-			{
-				if(events&(1<<i))
-				{
-					printk("rbv - bashing source %d\n",
-						i);
-					via_write(via, rIER, 1<<i);
-					via_write(via, rIFR, (1<<i) | rbv_clear);
-				}
-			}
-		        break;
-		}
-	}
-	while(events);
-#if 0
-	scsi_mac_polled();
-#endif
-}
-
-/*
- *	Nubus / SCSI interrupts; OSS style
- *	The OSS is even more different than the RBV. OSS appears to stand for 
- *	Obscenely Screwed Silicon ... 
- *
- *	Latest NetBSD sources suggest the OSS should behave like a RBV, but 
- *	that's probably true for the 0x203 offset (Nubus/ADB-SWIM IOP) at best
- */
- 
-void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int srcidx = IRQ_IDX(irq) - 1;	/* MUST be 1 !! */
-	volatile unsigned char *via = oss_regp;
-	unsigned char events=(via_read(via, oIFR))&0x03;
-	unsigned char nub_ev=(via_read(via, nIFR))&0x4F;
-	unsigned char adb_ev;
-	int i;
-	int ct = 0;
-	struct irqhandler *via_handler = handler_table[srcidx];
-	struct irqparam   *via_param   = param_table[srcidx];
-
-        /* shouldn't we disable interrupts here ?? */
-
-	adb_ev = nub_ev & 0x40;
-	nub_ev &= 0x3F;
-
-	/*
-	 *	Shouldnt happen
-	 */
-
-	if (events==0 && adb_ev==0 && nub_ev==0)
-	{
-		printk("oss_irq: nothing pending, flags %x %x!\n",
-			via_read(via, oIFR), via_read(via, nIFR));
-		rbv_irqs[7]++;
-		return;
-	}
-
-#ifdef DEBUG_VIA	
-	/*
-	 * limited verbosity for RBV interrupts (add more if needed)
-	 */
-	if ( events != 1<<3 )		/* SCSI IRQ */
-		printk("oss_irq: irq %d srcidx+1 %d events %x %x %x !\n", irq, srcidx+1, 
-			events, adb_ev, nub_ev);
-#endif
-
-	/* 
-	 * OSS priorities: call ADB handler first if registered, other events,
-	 * then Nubus 
-	 * ADB: yet to be implemented!
-	 */
-
-	/*
-	 * ADB: try to shutup the IOP 
-	 */
-	if (adb_ev) {
-		printk("Hands off ! Don't press this button ever again !!!\n");
-		via_write(via, 6, 0);
-	}
-
-	do {
-		/*
-		 *	Clear the pending flags
-		 *	How exactly is that supposed to work ??
-		 */
-
-		/*
-		 *	Now see what bits are raised
-		 */
-		 
-		for(i=0;i<7;i++)
-		{
-			/* HACK HACK: map to bit number in OSS register */
-			int irqidx = oss_map[i];
-			/* determine machspec. irq no. */
-			int irq = (srcidx+1)* 8 + i;
-		        /* call corresponding handlers */
-		        if ( (events&(1<<irqidx)) && 		/* bit set*/
-		             (via_read(via, irqidx+8)&0x7) ) {	/* irq enabled */
-			        if (irq_flags[srcidx].disabled & (1<<i)) {
-					if (!irq_flags[srcidx].pending&(1<<i))
-						rbv_irqs[i]++;
-				        /* irq disabled -> mark pending */
-				        irq_flags[srcidx].pending |= (1<<i);
-				} else {
-					rbv_irqs[i]++;
-				        /* irq enabled -> call handler */
-				        (via_handler[i].handler)(irq, via, regs);
-				}
-			}
-			/* and call handlers for pending irqs - first ?? */
-			if (    (irq_flags[srcidx].pending  & (1<<i))
-			    && !(irq_flags[srcidx].disabled & (1<<i)) ) {
-				/* call handler for re-enabled irq */
-			        (via_handler[i].handler)(irq, via, regs);
-				/* and clear pending flag :-) */
-				irq_flags[srcidx].pending  &= ~(1<<i);
-			}
-		}
-	
-		/*
-		 *	And done ... check for more punishment!
-		 */
-
-		events=(via_read(via, oIFR)/*&via_read(via,rIER)*/)&0x03;
-		ct++;
-		if(events && ct>8)
-		{
-		        printk("oss: stuck events %x\n",events);
-			for(i=0;i<7;i++)
-			{
-				if(events&(1<<i))
-				{
-					printk("oss - bashing source %d\n",
-						i);
-					/* that should disable it */
-					via_write(via, 8+i, 0);
-				}
-			}
-		        break;
-		}
-	}
-	while(events);
-#if 0
-	scsi_mac_polled();
-#endif
-
-	if (nub_ev)
-		oss_do_nubus(irq, via, regs);
-
-}
-
-/*
- *	Unexpected slot interrupt
- */
- 
-void nubus_wtf(int slot, void *via, struct pt_regs *regs)
-{
-#ifdef DEBUG_NUBUS_SPURIOUS
-	if (console_loglevel > 6)
-		printk("Unexpected interrupt on nubus slot %d\n",slot);
-#endif
-}
-
-/*
  *	SCC master interrupt handler; sole purpose: pass the registered 
  *	async struct to the SCC handler proper.
  */
 
 void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-	int i;
-				/* 1+2: compatibility with PSC ! */
-	for (i = 1; i < 3; i++) /* currently only these two used */
-		if (scc_handler[i].handler != mac_default_handler) {
-			(scc_handler[i].handler)(i, scc_handler[i].dev_id, regs);
-			scc_irqs[i]++;
-		}
-}
-
-/*
- *	PSC interrupt handler
- */
-
-void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int srcidx = IRQ_IDX(irq) - 1;
-	volatile unsigned char *via = psc_regp;
-	unsigned int pIFR = 0x100 + 0x10*srcidx;
-	unsigned int pIER = 0x104 + 0x10*srcidx;
-	unsigned char events=(via_read(via, pIFR)&via_read(via,pIER))&0xF;
-	int i;
-	int ct = 0;
-	struct irqhandler *via_handler = handler_table[srcidx];
-	struct irqparam   *via_param   = param_table[srcidx];
-
-        /* shouldn't we disable interrupts here ?? */
-
-	
-	/*
-	 *	Shouldnt happen
-	 */
-	 
-	if(events==0)
-	{
-#ifdef DEBUG_VIA
-		printk("psc_irq: nothing pending, flags %x mask %x!\n",
-			via_read(via, pIFR), via_read(via,pIER));
-#endif
-		mac_irqs[srcidx][7]++;
-		return;
-	}
-
-#ifdef DEBUG_VIA	
-	/*
-	 * limited verbosity for PSC interrupts (add more if needed)
-	 */
-	if ( srcidx == 1 && events != 1<<3 && events != 1<<1 )		/* SCSI IRQ */
-		printk("psc_irq: irq %d srcidx+1 %d events %x !\n", irq, srcidx+1, events);
-#endif
-
-	/* to be changed, possibly: for each non'masked', enabled IRQ, read 
-	 * flag bit, ack and call handler ...
-         * Currently: all pending irqs ack'ed en bloc.
-	 * If ack for masked IRQ required: keep 'pending' info separate.
-	 */
-
-	do {
-		/*
-		 *	Clear the pending flag
-		 */
-		 
-		/* via_write(via, pIFR, events); */
-		 
-		/*
-		 *	Now see what bits are raised
-		 */
-		 
-		for(i=0;i<7;i++)
-		{
-			/* determine machspec. irq no. */
-			int irq = (srcidx+1)* 8 + i;
-		        /* call corresponding handlers */
-		        if (events&(1<<i)) {
-			        if (irq_flags[srcidx].disabled & (1<<i)) {
-					if (!irq_flags[srcidx].pending&(1<<i))
-						mac_irqs[srcidx][i]++;
-				        /* irq disabled -> mark pending */
-				        irq_flags[srcidx].pending |= (1<<i);
-				} else {
-					mac_irqs[srcidx][i]++;
-				        /* irq enabled -> call handler */
-				        (via_handler[i].handler)(irq, via, regs);
-				}
-			}
-			/* and call handlers for pending irqs - first ?? */
-			if (    (irq_flags[srcidx].pending  & (1<<i))
-			    && !(irq_flags[srcidx].disabled & (1<<i)) ) {
-				/* call handler for re-enabled irq */
-			        (via_handler[i].handler)(irq, via, regs);
-				/* and clear pending flag :-) */
-				irq_flags[srcidx].pending  &= ~(1<<i);
-			}
-		}
-
-		/*
-		 *	And done ... check for more punishment!
-		 */
-
-		events=(via_read(via,pIFR)&via_read(via,pIER))&0x7F;
-		ct++;
-		if(events && ct>8)
-		{
-		        printk("psc: stuck events %x\n",events);
-			for(i=0;i<7;i++)
-			{
-				if(events&(1<<i))
-				{
-					printk("psc - bashing source %d\n",
-						i);
-					via_write(via, pIER, 1<<i);
-					/* via_write(via, pIFR, (1<<i)); */
-				}
-			}
-		        break;
-		}
-	}
-	while(events);
-}
-
-
-/*
- *	Nubus handling
- *      Caution: slot numbers are currently 'hardcoded' to the range 9-15!
- *      In general, the same request_irq() functions as above can be used if
- *      the interrupt numbers specifed in macints.h are used.
- */
- 
-static int nubus_active=0;
- 
-int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct pt_regs *))
-{
-	slot-=9;
-/*	printk("Nubus request irq for slot %d\n",slot);*/
-	if(nubus_handler[slot].handler!=nubus_wtf)
-		return -EBUSY;
-	nubus_handler[slot].handler=handler;
-	nubus_handler[slot].dev_id =dev_id;
-	nubus_param[slot].flags    = IRQ_FLG_LOCK;
-	nubus_param[slot].devname  = "nubus slot";
-
-	/* 
-	 * if no nubus int. was active previously: register the main nubus irq
-	 * handler now!
-	 */
-
-	if (!nubus_active && !via2_is_oss) {
-		request_irq(IRQ_MAC_NUBUS, via_do_nubus, IRQ_FLG_LOCK, 
-			    "nubus dispatch", via_do_nubus);
-		mac_turnon_irq(IRQ_MAC_NUBUS);
-	}
-
-	nubus_active|=1<<slot;
-/*	printk("program slot %d\n",slot);*/
-/*	printk("via2=%p\n",via2);*/
-#if 0
-	via_write(via2, vDirA, 
-		via_read(via2, vDirA)|(1<<slot));
-	via_write(via2, vBufA, 0);
-#endif		
-	if (via2_is_oss)
-		via_write(oss_regp, slot, 2);
-	else if (!via2_is_rbv) {
-		/* Make sure the bit is an input */
-		via_write(via2_regp, vDirA, 
-			via_read(via2_regp, vDirA)&~(1<<slot));
-	}
-/*	printk("nubus irq on\n");*/
-	return 0;
-}
-
-int nubus_free_irq(int slot)
-{
-	slot-=9;
-	nubus_active&=~(1<<slot);
-	nubus_handler[slot].handler=nubus_wtf;
-	nubus_handler[slot].dev_id = NULL;
-	nubus_param[slot].flags    = IRQ_FLG_STD;
-	nubus_param[slot].devname  = NULL;
-
-	if (via2_is_rbv)
-		via_write(rbv_regp, rBufA, 1<<slot);
-	else if (via2_is_oss)
-		via_write(oss_regp, slot, 0);
-	else {
-		via_write(via2_regp, vDirA, 
-			via_read(via2_regp, vDirA)|(1<<slot));
-		via_write(via2_regp, vBufA, 1<<slot);
-		via_write(via2_regp, vDirA, 
-			via_read(via2_regp, vDirA)&~(1<<slot));
-	}
-	return 0;
-}
-
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-/*
- * IDE interrupt hook
- */
-extern void (*mac_ide_intr_hook)(int, void *, struct pt_regs *);
-extern int (*mac_ide_irq_p_hook)(void);
-#endif
-
-/*
- * Nubus dispatch handler - VIA/RBV style
- */
-static void via_do_nubus(int slot, void *via, struct pt_regs *regs)
-{
-	unsigned char map, allints;
-	int i;
-	int ct=0;
-	int ide_pending = 0;
-		
-	/* lock the nubus interrupt */
-	/* That's just 'clear Nubus IRQ bit in VIA2' BTW. Pretty obsolete ? */
-	if (via2_is_rbv) 
-		via_write(rbv_regp, rIFR, 0x82);
-	else
-		via_write(via2_regp, vIFR, 0x82);
-	
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	/* IDE hack */
-	if (mac_ide_intr_hook) {
-		/* 'slot' is lacking the machspec bit in 2.0 */
-		/* need to pass proper dev_id = hwgroup here */
-		mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
-		mac_ide_irqs++;
-	}
-#endif
-
-	while(1)
-	{
-		if (via2_is_rbv)
-			allints = ~via_read(rbv_regp, rBufA);
-		else
-			allints = ~via_read(via2_regp, vBufA);
-		
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-		if (mac_ide_irq_p_hook)
-			ide_pending = mac_ide_irq_p_hook();
-#endif
-
-		if ( (map = (allints&nubus_active)) == 0 
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-		      && !ide_pending 
-#endif
-							) 
-		{
-			if (ct == 0) {
-#ifdef DEBUG_VIA_NUBUS
-				if (console_loglevel > 5)
-					printk("nubus_irq: nothing pending, map %x mask %x active %x\n", 
-						allints, nubus_active, map);
-#endif
-				nubus_irqs[7]++;
-			}
-			/* clear it */
-			if (allints)
-				if (via2_is_rbv)
-					via_write(rbv_regp, rIFR, 0x02);
-				else
-					via_write(via2_regp, vIFR, 0x02);
-			break;
-		}
-
-#ifdef DEBUG_VIA_NUBUS
-		if (console_loglevel > 6)
-			printk("nubus_irq: map %x mask %x active %x\n", 
-				allints, nubus_active, map);
-#endif
-
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-		if (mac_ide_intr_hook && ide_pending) {
-			mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
-			mac_ide_irqs++;
-		}
-#endif
-
-		if(ct++>2)
-		{
-			if (console_loglevel > 5)
-				printk("nubus stuck events - %x/%x/%x ide %x\n", 
-				allints, nubus_active, map, ide_pending);
-			nubus_stuck_events++;
-
-			return;
-		}
-
-		for(i=0;i<7;i++)
-		{
-			if(map&(1<<i))
-			{
-				nubus_irqs[i]++;
-				(nubus_handler[i].handler)(i+9, nubus_handler[i].dev_id, regs);
-			}
-		}
-		/* clear it */
-		if (via2_is_rbv)
-			via_write(rbv_regp, rIFR, 0x02);
-		else
-			via_write(via2_regp, vIFR, 0x02);
-
-	}
-	
-	/* And done */
-}
-
-/*
- * Nubus dispatch handler - OSS style
- */
-static void oss_do_nubus(int slot, void *via, struct pt_regs *regs)
-{
-	unsigned char map;
-	int i;
-	int ct=0;
-
-/*	printk("nubus interrupt\n");*/
-		
-#if 0
-	/* lock the nubus interrupt */
-	if (via2_is_rbv) 
-		via_write(rbv_regp, rIFR, 0x82);
-	else
-		via_write(via2_regp, vIFR, 0x82);
-#endif
-
-	/* IDE hack for Quadra: uses Nubus interrupt without any slot bit set */
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-	if (mac_ide_intr_hook)
-		mac_ide_intr_hook(IRQ_MAC_NUBUS, via, regs);
-#endif
-	
-	while(1)
-	{
-		/* pending events */
-		map=(via_read(via, nIFR))&0x3F;
-		
-#ifdef DEBUG_VIA_NUBUS
-		printk("nubus_irq: map %x mask %x\n", map, nubus_active);
-#endif
-		if( (map = (map&nubus_active)) ==0 ) {
-			if (ct == 0) {
-#ifdef CONFIG_BLK_DEV_MAC_IDE
-				if (!mac_ide_intr_hook)
-					printk("nubus_irq: nothing pending, map %x mask %x\n", 
-						map, nubus_active);
-#endif
-				nubus_irqs[7]++;
-			}
-			break;
-		}
-
-		if(ct++>2)
-		{
-#if 0
-			printk("nubus stuck events - %d/%d\n", map, nubus_active);
-#endif
-			return;
-		}
-
-		for(i=0;i<7;i++)
-		{
-			if(map&(1<<i))
-			{
-				nubus_irqs[i]++;
-				/* call handler */
-				(nubus_handler[i].handler)((i+9), nubus_handler[i].dev_id, regs);
-				/* clear interrupt ?? */
-#if 0
-				via_write(oss_regp, i, 0);
-#endif
-			}
-		}
-		/* clear it */ 
-#if 0
-		via_write(oss_regp, nIFR, map);
-#endif
-	}
-	
-	/* And done */
+	mac_do_irq_list(IRQ_SCCA, regs);
+	mac_do_irq_list(IRQ_SCCB, regs);
 }
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/oss.c linux/arch/m68k/mac/oss.c
--- v2.3.16/linux/arch/m68k/mac/oss.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/oss.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,314 @@
+/*
+ *	OSS handling
+ *	Written by Joshua M. Thompson (funaho@jurai.org)
+ *
+ *
+ *	This chip is used in the IIfx in place of VIA #2. It acts like a fancy
+ *	VIA chip with prorammable interrupt levels.
+ *
+ * 990502 (jmt) - Major rewrite for new interrupt architecture as well as some
+ *		  recent insights into OSS operational details.
+ * 990610 (jmt) - Now taking fulll advantage of the OSS. Interrupts are mapped
+ *		  to mostly match the A/UX interrupt scheme supported on the
+ *		  VIA side. Also added support for enabling the ISM irq again
+ *		  since we now have a functional IOP manager.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/bootinfo.h> 
+#include <asm/machw.h> 
+#include <asm/macintosh.h> 
+#include <asm/macints.h>
+#include <asm/mac_via.h>
+#include <asm/mac_oss.h>
+
+int oss_present;
+volatile struct mac_oss *oss;
+
+void oss_irq(int, void *, struct pt_regs *);
+void oss_nubus_irq(int, void *, struct pt_regs *);
+
+extern void via1_irq(int, void *, struct pt_regs *);
+extern void mac_SCC_handler(int, void *, struct pt_regs *);
+extern int console_loglevel;
+
+/*
+ * Initialize the OSS
+ *
+ * The OSS "detection" code is actually in via_init() which is always called
+ * before us. Thus we can count on oss_present being valid on entry.
+ */
+
+void __init oss_init(void)
+{
+	int i;
+
+	if (!oss_present) return;
+
+	oss = (struct mac_oss *) OSS_BASE;
+
+	/* Disable all interrupts. Unlike a VIA it looks like we    */
+	/* do this by setting the source's interrupt level to zero. */
+
+	for (i = 0; i <= OSS_NUM_SOURCES; i++) {
+		oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+	}
+	/* If we disable VIA1 here, we never really handle it... */
+	oss->irq_level[OSS_VIA1] = OSS_IRQLEV_VIA1;
+}
+
+/*
+ * Register the OSS and NuBus interrupt dispatchers.
+ */
+
+void __init oss_register_interrupts(void)
+{
+	request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK,
+		    "OSS SCSI Dispatch", (void *) oss);
+	request_irq(OSS_IRQLEV_IOPSCC, mac_SCC_handler, IRQ_FLG_LOCK,
+		    "SCC Dispatch", mac_SCC_handler);
+	request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK,
+		    "Nubus Dispatch", (void *) oss);
+	request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK,
+		    "OSS Sound Dispatch", (void *) oss);
+	request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK,
+		    "VIA1 Dispatch", (void *) via1);
+}
+
+/*
+ * Initialize OSS for Nubus access
+ */
+
+void __init oss_nubus_init(void)
+{
+}
+
+/*
+ * Turn off the power via the ROM control register
+ *
+ * FIXME: not sure how this is supposed to work exactly...
+ */
+
+void oss_poweroff(void)
+{
+	oss->rom_ctrl = OSS_POWEROFF;
+
+	/* We should never make it this far... */
+
+	printk ("It is now safe to switch off your machine.\n");
+	while(1);
+}
+
+/*
+ * Handle miscellaneous OSS interrupts. Right now that's just sound
+ * and SCSI; everything else is routed to its own autovector IRQ.
+ */
+ 
+void oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int events;
+
+	events = oss->irq_pending & (OSS_IP_SOUND|OSS_IP_SCSI);
+	if (!events) return;
+
+#ifdef DEBUG_IRQS	
+	if ((console_loglevel == 10) && !(events & OSS_IP_SCSI)) {
+		printk("oss_irq: irq %d events = 0x%04X\n", irq,
+			(int) oss->irq_pending);
+	}
+#endif
+	/* FIXME: how do you clear a pending IRQ?    */
+
+	if (events & OSS_IP_SOUND) {
+		/* FIXME: call sound handler */
+		oss->irq_pending &= ~OSS_IP_SOUND;
+	} else if (events & OSS_IP_SCSI) {
+		oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+		mac_do_irq_list(IRQ_MAC_SCSI, regs);
+		oss->irq_pending &= ~OSS_IP_SCSI;
+		oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+	} else {
+		/* FIXME: error check here? */
+	}
+}
+
+/*
+ * Nubus IRQ handler, OSS style
+ *
+ * Unlike the VIA/RBV this is on its own autovector interupt level.
+ */
+
+void oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int events, irq_bit, i;
+
+	events = oss->irq_pending & OSS_IP_NUBUS;
+	if (!events) return;
+
+#ifdef DEBUG_NUBUS_INT
+	if (console_loglevel > 7) {
+		printk("oss_nubus_irq: events = 0x%04X\n", events);
+	}
+#endif
+	/* There are only six slots on the OSS, not seven */
+
+	for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
+		if (events & irq_bit) {
+			oss->irq_level[i] = OSS_IRQLEV_DISABLED;
+			mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+			oss->irq_pending &= ~irq_bit;
+			oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+		}
+	}
+}
+
+/*
+ * Enable an OSS interrupt
+ *
+ * It looks messy but it's rather straightforward. The switch() statement
+ * just maps the machspec interrupt numbers to the right OSS interrupt
+ * source (if the OSS handles that interrupt) and then sets the interrupt
+ * level for that source to nonzero, thus enabling the interrupt.
+ */
+
+void oss_irq_enable(int irq) {
+#ifdef DEBUG_IRQUSE
+	printk("oss_irq_enable(%d)\n", irq);
+#endif
+	switch(irq) {
+		case IRQ_SCC:
+		case IRQ_SCCA:
+		case IRQ_SCCB:
+			oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_IOPSCC;
+			break;
+		case IRQ_MAC_ADB:
+			oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_IOPISM;
+			break;
+		case IRQ_MAC_SCSI:
+			oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+			break;
+		case IRQ_NUBUS_9:
+		case IRQ_NUBUS_A:
+		case IRQ_NUBUS_B:
+		case IRQ_NUBUS_C:
+		case IRQ_NUBUS_D:
+		case IRQ_NUBUS_E:
+			irq -= NUBUS_SOURCE_BASE;
+			oss->irq_level[irq] = OSS_IRQLEV_NUBUS;
+			break;
+#ifdef DEBUG_IRQUSE
+		default:
+			printk("%s unknown irq %d\n",__FUNCTION__, irq);
+			break;
+#endif
+	}
+}
+
+/*
+ * Disable an OSS interrupt
+ *
+ * Same as above except we set the source's interrupt level to zero,
+ * to disable the interrupt.
+ */
+
+void oss_irq_disable(int irq) {
+#ifdef DEBUG_IRQUSE
+	printk("oss_irq_disable(%d)\n", irq);
+#endif
+	switch(irq) {
+		case IRQ_SCC:
+		case IRQ_SCCA:
+		case IRQ_SCCB:
+			oss->irq_level[OSS_IOPSCC] = OSS_IRQLEV_DISABLED;
+			break;
+		case IRQ_MAC_ADB:
+			oss->irq_level[OSS_IOPISM] = OSS_IRQLEV_DISABLED;
+			break;
+		case IRQ_MAC_SCSI:
+			oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
+			break;
+		case IRQ_NUBUS_9:
+		case IRQ_NUBUS_A:
+		case IRQ_NUBUS_B:
+		case IRQ_NUBUS_C:
+		case IRQ_NUBUS_D:
+		case IRQ_NUBUS_E:
+			irq -= NUBUS_SOURCE_BASE;
+			oss->irq_level[irq] = OSS_IRQLEV_DISABLED;
+			break;
+#ifdef DEBUG_IRQUSE
+		default:
+			printk("%s unknown irq %d\n", __FUNCTION__, irq);
+			break;
+#endif
+	}
+}
+
+/*
+ * Clear an OSS interrupt
+ *
+ * Not sure if this works or not but it's the only method I could
+ * think of based on the contents of the mac_oss structure.
+ */
+
+void oss_irq_clear(int irq) {
+	/* FIXME: how to do this on OSS? */
+	switch(irq) {
+		case IRQ_SCC:
+		case IRQ_SCCA:
+		case IRQ_SCCB:
+			oss->irq_pending &= ~OSS_IP_IOPSCC;
+			break;
+		case IRQ_MAC_ADB:
+			oss->irq_pending &= ~OSS_IP_IOPISM;
+			break;
+		case IRQ_MAC_SCSI:
+			oss->irq_pending &= ~OSS_IP_SCSI;
+			break;
+		case IRQ_NUBUS_9:
+		case IRQ_NUBUS_A:
+		case IRQ_NUBUS_B:
+		case IRQ_NUBUS_C:
+		case IRQ_NUBUS_D:
+		case IRQ_NUBUS_E:
+			irq -= NUBUS_SOURCE_BASE;
+			oss->irq_pending &= ~(1 << irq);
+			break;
+	}
+}
+
+/*
+ * Check to see if a specific OSS interrupt is pending
+ */
+
+int oss_irq_pending(int irq)
+{
+	switch(irq) {
+		case IRQ_SCC:
+		case IRQ_SCCA:
+		case IRQ_SCCB:
+			return oss->irq_pending & OSS_IP_IOPSCC;
+			break;
+		case IRQ_MAC_ADB:
+			return oss->irq_pending & OSS_IP_IOPISM;
+			break;
+		case IRQ_MAC_SCSI:
+			return oss->irq_pending & OSS_IP_SCSI;
+			break;
+		case IRQ_NUBUS_9:
+		case IRQ_NUBUS_A:
+		case IRQ_NUBUS_B:
+		case IRQ_NUBUS_C:
+		case IRQ_NUBUS_D:
+		case IRQ_NUBUS_E:
+			irq -= NUBUS_SOURCE_BASE;
+			return oss->irq_pending & (1 << irq);
+			break;
+	}
+	return 0;
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/psc.c linux/arch/m68k/mac/psc.c
--- v2.3.16/linux/arch/m68k/mac/psc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/psc.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,203 @@
+/*
+ *	Apple Peripheral System Controller (PSC)
+ *
+ *	The PSC is used on the AV Macs to control IO functions not handled
+ *	by the VIAs (Ethernet, DSP, SCC).
+ *
+ * TO DO:
+ *
+ * Try to figure out what's going on in pIFR5 and pIFR6. There seem to be
+ * persisant interrupt conditions in those registers and I have no idea what
+ * they are. Granted it doesn't affect since we're not enabling any interrupts
+ * on those levels at the moment, but it would be nice to know. I have a feeling
+ * they aren't actually interrupt lines but data lines (to the DSP?)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/traps.h>
+#include <asm/bootinfo.h> 
+#include <asm/macintosh.h> 
+#include <asm/macints.h> 
+#include <asm/mac_psc.h>
+
+#define DEBUG_PSC
+
+int psc_present;
+volatile __u8 *psc;
+
+void psc_irq(int, void *, struct pt_regs *);
+
+extern int console_loglevel;
+
+/*
+ * Debugging dump, used in various places to see what's going on.
+ */
+
+void psc_debug_dump(void)
+{
+	int	i;
+
+	if (!psc_present) return;
+	for (i = 0x30 ; i < 0x70 ; i += 0x10) {
+		printk("PSC #%d:  IFR = 0x%02X IER = 0x%02X\n",
+			i >> 4,
+			(int) psc_read_byte(pIFRbase + i),
+			(int) psc_read_byte(pIERbase + i));
+	}
+}
+
+/*
+ * Try to kill all DMA channels on the PSC. Not sure how this his
+ * supposed to work; this is code lifted from macmace.c and then
+ * expanded to cover what I think are the other 7 channels.
+ */
+
+void psc_dma_die_die_die(void)
+{
+	int i;
+
+	printk("Killing all PSC DMA channels...");
+	for (i = 0 ; i < 9 ; i++) {
+		psc_write_word(PSC_CTL_BASE + (i << 4), 0x8800);
+		psc_write_word(PSC_CTL_BASE + (i << 4), 0x1000);
+		psc_write_word(PSC_CMD_BASE + (i << 5), 0x1100);
+		psc_write_word(PSC_CMD_BASE + (i << 5) + 0x10, 0x1100);
+	}
+	printk("done!\n");
+}
+
+/*
+ * Initialize the PSC. For now this just involves shutting down all
+ * interrupt sources using the IERs.
+ */
+
+void __init psc_init(void)
+{
+	int i;
+
+	if (macintosh_config->ident != MAC_MODEL_C660
+	 && macintosh_config->ident != MAC_MODEL_Q840)
+	{
+		psc = NULL;
+		psc_present = 0;
+		return;
+	}
+
+	/*
+	 * The PSC is always at the same spot, but using psc
+	 * keeps things consisant with the psc_xxxx functions.
+	 */
+
+	psc = (void *) PSC_BASE;
+	psc_present = 1;
+
+	printk("PSC detected at %p\n", psc);
+
+	psc_dma_die_die_die();
+
+#ifdef DEBUG_PSC
+	psc_debug_dump();
+#endif
+	/*
+	 * Mask and clear all possible interrupts
+	 */
+
+	for (i = 0x30 ; i < 0x70 ; i += 0x10) {
+		psc_write_byte(pIERbase + i, 0x0F);
+		psc_write_byte(pIFRbase + i, 0x0F);
+	}
+}
+
+/*
+ * Register the PSC interrupt dispatchers for autovector interrupts 3-6.
+ */
+
+void __init psc_register_interrupts(void)
+{
+	request_irq(3, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+		    (void *) 0x30);
+	request_irq(4, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+		    (void *) 0x40);
+	request_irq(5, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+		    (void *) 0x50);
+	request_irq(6, psc_irq, IRQ_FLG_LOCK, "PSC Dispatch",
+		    (void *) 0x60);
+}
+
+/*
+ * PSC interrupt handler. It's a lot like the VIA interrupt handler.
+ */
+
+void psc_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int pIFR	= pIFRbase + ((int) dev_id);
+	int pIER	= pIERbase + ((int) dev_id);
+	int base_irq;
+	int irq_bit,i;
+	unsigned char events;
+
+	irq -= VEC_SPUR;
+	base_irq = irq << 3;
+
+#ifdef DEBUG_IRQS
+	printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
+		irq, (int) psc_read_byte(pIFR), (int) psc_read_byte(pIER));
+#endif
+
+	events = psc_read_byte(pIFR) & psc_read_byte(pIER) & 0xF;
+	if (!events) return;
+
+	for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
+	        if (events & irq_bit) {
+			psc_write_byte(pIER, irq_bit);
+			mac_do_irq_list(base_irq + i, regs);
+			psc_write_byte(pIFR, irq_bit);
+			psc_write_byte(pIER, irq_bit | 0x80);
+		}
+	}
+}
+
+void psc_irq_enable(int irq) {
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int pIER	= pIERbase + (irq_src << 4);
+
+#ifdef DEBUG_IRQUSE
+	printk("psc_irq_enable(%d)\n", irq);
+#endif
+	psc_write_byte(pIER, (1 << irq_idx) | 0x80);
+}
+
+void psc_irq_disable(int irq) {
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int pIER	= pIERbase + (irq_src << 4);
+
+#ifdef DEBUG_IRQUSE
+	printk("psc_irq_disable(%d)\n", irq);
+#endif
+	psc_write_byte(pIER, 1 << irq_idx);
+}
+
+void psc_irq_clear(int irq) {
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int pIFR	= pIERbase + (irq_src << 4);
+
+	psc_write_byte(pIFR, 1 << irq_idx);
+}
+
+int psc_irq_pending(int irq)
+{
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int pIFR	= pIERbase + (irq_src << 4);
+
+	return psc_read_byte(pIFR) & (1 << irq_idx);
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/via.c linux/arch/m68k/mac/via.c
--- v2.3.16/linux/arch/m68k/mac/via.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mac/via.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,774 @@
+/*
+ *	6522 Versatile Interface Adapter (VIA)
+ *
+ *	There are two of these on the Mac II. Some IRQ's are vectored
+ *	via them as are assorted bits and bobs - eg RTC, ADB.
+ *
+ * CSA: Motorola seems to have removed documentation on the 6522 from
+ * their web site; try
+ *     http://nerini.drf.com/vectrex/other/text/chips/6522/
+ *     http://www.zymurgy.net/classic/vic20/vicdet1.htm
+ * and
+ *     http://193.23.168.87/mikro_laborversuche/via_iobaustein/via6522_1.html
+ * for info.  A full-text web search on 6522 AND VIA will probably also
+ * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
+ *
+ * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
+ * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <asm/traps.h>
+#include <asm/bootinfo.h> 
+#include <asm/macintosh.h> 
+#include <asm/macints.h>
+#include <asm/machw.h> 
+#include <asm/mac_via.h>
+#include <asm/mac_psc.h>
+
+volatile __u8 *via1, *via2;
+#if 0
+/* See note in mac_via.h about how this is possibly not useful */
+volatile long *via_memory_bogon=(long *)&via_memory_bogon;
+#endif
+int  rbv_present,via_alt_mapping;
+__u8 rbv_clear;
+
+/*
+ * Globals for accessing the VIA chip registers without having to
+ * check if we're hitting a real VIA or an RBV. Normally you could
+ * just hit the combined register (ie, vIER|rIER) but that seems to
+ * break on AV Macs...probably because they actually decode more than
+ * eight address bits. Why can't Apple engineers at least be
+ * _consistantly_ lazy?                          - 1999-05-21 (jmt)
+ */
+
+static int gIER,gIFR,gBufA,gBufB;
+
+/*
+ * Timer defs.
+ */
+
+#define TICK_SIZE		10000
+#define MAC_CLOCK_TICK		(783300/HZ)		/* ticks per HZ */
+#define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
+#define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
+
+static int  nubus_active;
+
+void via_debug_dump(void);
+void via1_irq(int, void *, struct pt_regs *);
+void via2_irq(int, void *, struct pt_regs *);
+void via_nubus_irq(int, void *, struct pt_regs *);
+void via_irq_enable(int irq);
+void via_irq_disable(int irq);
+void via_irq_clear(int irq);
+
+extern void mac_bang(int, void *, struct pt_regs *);
+extern void mac_SCC_handler(int, void *, struct pt_regs *);
+extern int console_loglevel;
+extern int oss_present;
+
+/*
+ * Initialize the VIAs
+ *
+ * First we figure out where they actually _are_ as well as what type of
+ * VIA we have for VIA2 (it could be a real VIA or an RBV or even an OSS.)
+ * Then we pretty much clear them out and disable all IRQ sources.
+ *
+ * Note: the OSS is actually "detected" here and not in oss_init(). It just
+ *	 seems more logical to do it here since via_init() needs to know
+ *	 these things anyways.
+ */
+
+void __init via_init(void)
+{
+	switch(macintosh_config->via_type) {
+
+		/* IIci, IIsi, IIvx, IIvi (P6xx), LC series */
+
+		case MAC_VIA_IIci:	
+			via1 = (void *) VIA1_BASE;
+			if (macintosh_config->ident == MAC_MODEL_IIFX) {
+				via2 = NULL;
+				rbv_present = 0;
+				oss_present = 1;
+			} else {
+				via2 = (void *) RBV_BASE;
+				rbv_present = 1;
+				oss_present = 0;
+			}
+			if (macintosh_config->ident == MAC_MODEL_LCIII) {
+				rbv_clear = 0x00;
+			} else {
+				/* on most RBVs (& unlike the VIAs), you   */
+				/* need to set bit 7 when you write to IFR */
+				/* in order for your clear to occur.       */
+				rbv_clear = 0x80;
+			}
+			gIER = rIER;
+			gIFR = rIFR;
+			gBufA = rSIFR;
+			gBufB = rBufB;
+			break;
+
+		/* Quadra and early MacIIs agree on the VIA locations */
+
+		case MAC_VIA_QUADRA:
+		case MAC_VIA_II:
+			via1 = (void *) VIA1_BASE;
+			via2 = (void *) VIA2_BASE;
+			rbv_present = 0;
+			oss_present = 0;
+			rbv_clear = 0x00;
+			gIER = vIER;
+			gIFR = vIFR;
+			gBufA = vBufA;
+			gBufB = vBufB;
+			break;
+		default:
+			panic("UNKNOWN VIA TYPE");
+	}
+
+	printk("VIA1 at %p is a 6522 or clone\n", via1);
+
+	printk("VIA2 at %p is ", via2);
+	if (rbv_present) {
+		printk("an RBV\n");
+	} else if (oss_present) {
+		printk("an OSS\n");
+	} else {
+		printk("a 6522 or clone\n");
+	}
+
+#ifdef DEBUG_VIA
+	via_debug_dump();
+#endif
+
+	/*
+	 * Shut down all IRQ sources, reset the timers, and
+	 * kill the timer latch on VIA1.
+	 */
+
+	via1[vIER] = 0x7F;
+	via1[vIFR] = 0x7F;
+	via1[vT1LL] = 0;
+	via1[vT1LH] = 0;
+	via1[vT1CL] = 0;
+	via1[vT1CH] = 0;
+	via1[vT2CL] = 0;
+	via1[vT2CH] = 0;
+	via1[vACR] &= 0x3F;
+
+	/* 
+	 * SE/30: disable video IRQ
+	 * XXX: testing for SE/30 VBL
+	 */
+
+	if (macintosh_config->ident == MAC_MODEL_SE30) {
+		via1[vDirB] |= 0x40;
+		via1[vBufB] |= 0x40;
+	} 
+	
+	/*
+	 * Set the RTC bits to a known state: all lines to outputs and
+	 * RTC disabled (yes that's 0 to enable and 1 to disable).
+	 */
+
+	via1[vDirB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk | VIA1B_vRTCData);
+	via1[vBufB] |= (VIA1B_vRTCEnb | VIA1B_vRTCClk);
+
+	/* Everything below this point is VIA2/RBV only... */
+
+	if (oss_present) return;
+
+#if 1
+	/* Some machines support an alternate IRQ mapping that spreads  */
+	/* Ethernet and Sound out to their own autolevel IRQs and moves */
+	/* VIA1 to level 6. A/UX uses this mapping and we do too.  Note */
+	/* that the IIfx emulates this alternate mapping using the OSS. */
+
+	switch(macintosh_config->ident) {
+		case MAC_MODEL_C610:
+		case MAC_MODEL_Q610:
+		case MAC_MODEL_C650:
+		case MAC_MODEL_Q650:
+		case MAC_MODEL_Q700:
+		case MAC_MODEL_Q800:
+		case MAC_MODEL_Q900:
+		case MAC_MODEL_Q950:
+			via_alt_mapping = 1;
+			via1[vDirB] |= 0x40;
+			via1[vBufB] &= ~0x40;
+			break;
+		default:
+			via_alt_mapping = 0;
+			break;
+	}
+#else
+	/* The alernate IRQ mapping seems to just not work. Anyone with a   */
+	/* supported machine is welcome to take a stab at fixing it. It     */
+	/* _should_ work on the following Quadras: 610,650,700,800,900,950  */
+	/*                                               - 1999-06-12 (jmt) */
+
+	via_alt_mapping = 0;
+#endif
+
+	/*
+	 * Now initialize VIA2. For RBV we just kill all interrupts;
+	 * for a regular VIA we also reset the timers and stuff.
+	 */
+
+	via2[gIER] = 0x7F;
+	via2[gIFR] = 0x7F | rbv_clear;
+	if (!rbv_present) {
+		via2[vT1LL] = 0;
+		via2[vT1LH] = 0;
+		via2[vT1CL] = 0;
+		via2[vT1CH] = 0;
+		via2[vT2CL] = 0;
+		via2[vT2CH] = 0;
+		via2[vACR] &= 0x3F;
+	}
+}
+
+/*
+ * Start the 100 Hz clock
+ */
+
+void __init via_init_clock(void (*func)(int, void *, struct pt_regs *))
+{	
+	via1[vACR] |= 0x40;
+	via1[vT1LL] = MAC_CLOCK_LOW;
+	via1[vT1LH] = MAC_CLOCK_HIGH;
+	via1[vT1CL] = MAC_CLOCK_LOW;
+	via1[vT1CH] = MAC_CLOCK_HIGH;
+
+	request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
+}
+
+/*
+ * Register the interrupt dispatchers for VIA or RBV machines only.
+ */
+
+void __init via_register_interrupts(void)
+{
+	if (via_alt_mapping) {
+		request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+			    "Software IRQ", (void *) via1);
+		request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+			    "VIA1 Dispatch", (void *) via1);
+	} else {
+		request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+			    "VIA1 Dispatch", (void *) via1);
+#if 0 /* interferes with serial on some machines */
+		if (!psc_present) {
+			request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK,
+					"Off Switch", mac_bang);
+		}
+#endif
+	}
+	request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+		    "VIA2 Dispatch", (void *) via2);
+	if (!psc_present) {
+		request_irq(IRQ_AUTO_4, mac_SCC_handler, IRQ_FLG_LOCK,
+			    "SCC Dispatch", mac_SCC_handler);
+	}
+	request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST,
+			"Nubus Dispatch", (void *) via2);
+}
+
+/*
+ * Debugging dump, used in various places to see what's going on.
+ */
+
+void via_debug_dump(void)
+{
+	printk("VIA1: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+		(uint) via1[vDirA], (uint) via1[vDirB], (uint) via1[vACR]);
+	printk("         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
+		(uint) via1[vPCR], (uint) via1[vIFR], (uint) via1[vIER]);
+	if (oss_present) {
+		printk("VIA2: <OSS>\n");
+	} else if (rbv_present) {
+		printk("VIA2:  IFR = 0x%02X  IER = 0x%02X\n",
+			(uint) via2[rIFR], (uint) via2[rIER]);
+		printk("      SIFR = 0x%02X SIER = 0x%02X\n",
+			(uint) via2[rSIFR], (uint) via2[rSIER]);
+	} else {
+		printk("VIA2: DDRA = 0x%02X DDRB = 0x%02X ACR = 0x%02X\n",
+			(uint) via2[vDirA], (uint) via2[vDirB],
+			(uint) via2[vACR]);
+		printk("         PCR = 0x%02X  IFR = 0x%02X IER = 0x%02X\n",
+			(uint) via2[vPCR],
+			(uint) via2[vIFR], (uint) via2[vIER]);
+	}
+}
+
+/*
+ * This is always executed with interrupts disabled.
+ *
+ * TBI: get time offset between scheduling timer ticks
+ */
+
+unsigned long mac_gettimeoffset (void)
+{
+	unsigned long ticks, offset = 0;
+
+	/* read VIA1 timer 2 current value */
+	ticks = via1[vT1CL] | (via1[vT1CH] << 8);
+	/* The probability of underflow is less than 2% */
+	if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
+		/* Check for pending timer interrupt in VIA1 IFR */
+		if (via1[vIFR] & 0x40) offset = TICK_SIZE;
+
+	ticks = MAC_CLOCK_TICK - ticks;
+	ticks = ticks * 10000L / MAC_CLOCK_TICK;
+
+	return ticks + offset;
+}
+
+/*
+ * Flush the L2 cache on Macs that have it by flipping
+ * the system into 24-bit mode for an instant.
+ */
+
+void via_flush_cache(void)
+{
+	via2[gBufB] &= ~VIA2B_vMode32;
+	via2[gBufB] |= VIA2B_vMode32;
+}
+
+/*
+ * Return the status of the L2 cache on a IIci
+ */
+
+int via_get_cache_disable(void)
+{
+	/* Safeguard against being called accidentally */
+	if (!via2) {
+		printk(KERN_ERR "via_get_cache_disable called on a non-VIA machine!\n");
+		return 1;
+	}
+
+	return (int) via2[gBufB] & VIA2B_vCDis;
+}
+
+/*
+ * VIA-based power switch, for machines that support it.
+ */
+
+void via_poweroff(void)
+{
+	if (rbv_present) {
+		via2[rBufB] &= ~0x04;
+	} else {
+		/* Direction of vDirB is output */
+		via2[vDirB] |= 0x04;
+		/* Send a value of 0 on that line */
+		via2[vBufB] &= ~0x04;
+		/* Otherwise it prints "It is now.." then shuts off */
+		mdelay(1000);
+	}
+
+	/* We should never make it this far... */
+	printk ("It is now safe to switch off your machine.\n");
+	while(1);
+}
+
+/*
+ * Initialize VIA2 for Nubus access
+ */
+
+void __init via_nubus_init(void)
+{
+	nubus_active = 0;
+
+	/* unlock nubus transactions */
+
+	if (!rbv_present) {
+		/* set the line to be an output on non-RBV machines */
+		via2[vDirB] |= 0x02;
+	}
+	via2[gBufB] |= 0x02;
+
+	/* disable nubus slot interrupts. */
+	if (rbv_present) {
+		via2[rSIER] = 0x7F;	/* like VIA; bit 7=clr,set */
+	} else {
+		via2[vBufA] = 0xFF;	/* active low irqs, force high */
+		via2[vDirA] = 0xFF;	/* ddr to output. */
+	}
+}
+
+/*
+ * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
+ * via6522.c :-), disable/pending masks added.
+ *
+ * The new interrupt architecture in macints.c takes care of a lot of the
+ * gruntwork for us, including tallying the interrupts and calling the
+ * handlers on the linked list. All we need to do here is basically generate
+ * the machspec interrupt number after clearing the interrupt.
+ */
+
+void via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int irq_bit, i;
+	unsigned char events, mask;
+
+	irq -= VEC_SPUR;
+
+	mask = via1[vIER] & 0x7F;
+	if (!(events = via1[vIFR] & mask)) return;
+
+	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+		if (events & irq_bit) {
+			via1[vIER] = irq_bit;
+			mac_do_irq_list(VIA1_SOURCE_BASE + i, regs);
+			via1[vIFR] = irq_bit;
+			via1[vIER] = irq_bit | 0x80;
+		}
+
+	if (!oss_present) {
+		/* This (still) seems to be necessary to get IDE
+		   working.  However, if you enable VBL interrupts,
+		   you're screwed... */
+		/* FIXME: should we check the SLOTIRQ bit before
+                   pulling this stunt? */
+		/* No, it won't be set. that's why we're doing this. */
+		via_irq_disable(IRQ_MAC_NUBUS);
+		via_irq_clear(IRQ_MAC_NUBUS);
+		mac_do_irq_list(IRQ_MAC_NUBUS, regs);
+		via_irq_enable(IRQ_MAC_NUBUS);
+	}
+}
+
+void via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int irq_bit, i;
+	unsigned char events, mask;
+
+	irq -= VEC_SPUR;
+
+	mask = via2[gIER] & 0x7F;
+	if (!(events = via2[gIFR] & mask)) return;
+
+	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+		if (events & irq_bit) {
+			via2[gIER] = irq_bit;
+			mac_do_irq_list(VIA2_SOURCE_BASE + i, regs);
+			via2[gIFR] = irq_bit | rbv_clear;
+			via2[gIER] = irq_bit | 0x80;
+		}
+}
+
+/*
+ * Dispatch Nubus interrupts. We are called as a secondary dispatch by the
+ * VIA2 dispatcher as a fast interrupt handler.
+ */
+
+void via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+	int irq_bit, i;
+	unsigned char events;
+
+	if (!(events = ~via2[gBufA]  & nubus_active)) return;
+
+	for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
+		if (events & irq_bit) {
+			via_irq_disable(NUBUS_SOURCE_BASE + i);
+			mac_do_irq_list(NUBUS_SOURCE_BASE + i, regs);
+			via_irq_enable(NUBUS_SOURCE_BASE + i);
+		}
+	}
+}
+
+void via_irq_enable(int irq) {
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int irq_bit	= 1 << irq_idx;
+
+#ifdef DEBUG_IRQUSE
+	printk("via_irq_enable(%d)\n", irq);
+#endif
+
+	if (irq_src == 1) {
+		via1[vIER] = irq_bit | 0x80;
+	} else if (irq_src == 2) {
+		/*
+		 * Set vPCR for SCSI interrupts (but not on RBV)
+		 */
+		if ((irq_idx == 0) && !rbv_present) {
+			if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
+				/* CB2 (IRQ) indep. input, positive edge */
+				/* CA2 (DRQ) indep. input, positive edge */
+				via2[vPCR] = 0x66;
+			} else {
+				/* CB2 (IRQ) indep. input, negative edge */
+				/* CA2 (DRQ) indep. input, negative edge */
+				via2[vPCR] = 0x22;
+			}
+		}
+		via2[gIER] = irq_bit | 0x80;
+	} else if (irq_src == 7) {
+		if (rbv_present) {
+			/* enable the slot interrupt. SIER works like IER. */
+			via2[rSIER] = IER_SET_BIT(irq_idx);
+		} else {
+			/* Make sure the bit is an input, to enable the irq */
+			via2[vDirA] &= ~irq_bit;
+		}
+		nubus_active |= irq_bit;
+	}
+}
+
+void via_irq_disable(int irq) {
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int irq_bit	= 1 << irq_idx;
+
+#ifdef DEBUG_IRQUSE
+	printk("via_irq_disable(%d)\n", irq);
+#endif
+
+	if (irq_src == 1) {
+		via1[vIER] = irq_bit;
+	} else if (irq_src == 2) {
+		via2[gIER] = irq_bit;
+	} else if (irq_src == 7) {
+		if (rbv_present) {
+			/* disable the slot interrupt.  SIER works like IER. */
+			via2[rSIER] = IER_CLR_BIT(irq_idx);
+		} else {
+			/* disable the nubus irq by changing dir to output */
+			via2[vDirA] |= irq_bit;
+		}
+		nubus_active &= ~irq_bit;
+	}
+}
+
+void via_irq_clear(int irq) {
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int irq_bit	= 1 << irq_idx;
+
+	if (irq_src == 1) {
+		via1[vIFR] = irq_bit;
+	} else if (irq_src == 2) {
+		via2[gIFR] = irq_bit | rbv_clear;
+	} else if (irq_src == 7) {
+		/* FIXME: hmm.. */
+	}
+}
+
+/*
+ * Returns nonzero if an interrupt is pending on the given
+ * VIA/IRQ combination.
+ */
+
+int via_irq_pending(int irq)
+{
+	int irq_src	= IRQ_SRC(irq);
+	int irq_idx	= IRQ_IDX(irq);
+	int irq_bit	= 1 << irq_idx;
+
+	if (irq_src == 1) {
+		return via1[vIFR] & irq_bit;
+	} else if (irq_src == 2) {
+		return via2[gIFR] & irq_bit;
+	} else if (irq_src == 7) {
+		return ~via2[gBufA] & irq_bit;
+	}
+	return 0;
+}
+
+void via_scsi_clear(void)
+{
+	volatile unsigned char deep_magic;
+
+#ifdef DEBUG_IRQUSE
+	printk("via_scsi_clear()\n");
+#endif
+
+	/* We handle this in oss.c , but this gets called in mac_scsinew.c */
+	if(oss_present) return;
+
+	if (rbv_present) {
+		via2[rIFR] = (1<<3) | (1<<0) | rbv_clear;
+		deep_magic = via2[rBufB];
+	} else {
+		deep_magic = via2[vBufB];
+	}
+	mac_enable_irq(IRQ_MAC_SCSI);
+}
+
+/*
+ * PRAM/RTC access routines
+ *
+ * Must be called with interrupts disabled and
+ * the RTC should be enabled.
+ */
+
+static __u8 via_pram_readbyte(void)
+{
+	int	i,reg;
+	__u8	data;
+
+	reg = via1[vBufB] & ~VIA1B_vRTCClk;
+
+	/* Set the RTC data line to be an input. */
+
+	via1[vDirB] &= ~VIA1B_vRTCData;
+
+	/* The bits of the byte come out in MSB order */
+
+	data = 0;
+	for (i = 0 ; i < 8 ; i++) {
+		via1[vBufB] = reg;
+		via1[vBufB] = reg | VIA1B_vRTCClk;
+		data = (data << 1) | (via1[vBufB] & VIA1B_vRTCData);
+	}
+
+	/* Return RTC data line to output state */
+
+	via1[vDirB] |= VIA1B_vRTCData;
+
+	return data;
+}
+
+static void via_pram_writebyte(__u8 data)
+{
+	int	i,reg,bit;
+
+	reg = via1[vBufB] & ~(VIA1B_vRTCClk | VIA1B_vRTCData);
+
+	/* The bits of the byte go in in MSB order */
+
+	for (i = 0 ; i < 8 ; i++) {
+		bit = data & 0x80? 1 : 0;
+		data <<= 1;
+		via1[vBufB] = reg | bit;
+		via1[vBufB] = reg | bit | VIA1B_vRTCClk;
+	}
+}
+
+/*
+ * Execute a PRAM/RTC command. For read commands
+ * data should point to a one-byte buffer for the
+ * resulting data. For write commands it should point
+ * to the data byte to for the command.
+ *
+ * This function disables all interrupts while running.
+ */
+
+void via_pram_command(int command, __u8 *data)
+{
+	unsigned long cpu_flags;
+	int	is_read;
+
+	save_flags(cpu_flags);
+	cli();
+
+	/* Enable the RTC and make sure the strobe line is high */
+
+	via1[vBufB] = (via1[vBufB] | VIA1B_vRTCClk) & ~VIA1B_vRTCEnb;
+
+	if (command & 0xFF00) {		/* extended (two-byte) command */
+		via_pram_writebyte((command & 0xFF00) >> 8);
+		via_pram_writebyte(command & 0xFF);
+		is_read = command & 0x8000;
+	} else {			/* one-byte command */
+		via_pram_writebyte(command);
+		is_read = command & 0x80;
+	}
+	if (is_read) {
+		*data = via_pram_readbyte();
+	} else {
+		via_pram_writebyte(*data);
+	}
+
+	/* All done, disable the RTC */
+
+	via1[vBufB] |= VIA1B_vRTCEnb;
+
+	restore_flags(cpu_flags);
+}
+
+/*
+ * Return the current time in seconds since January 1, 1904.
+ *
+ * This only works on machines with the VIA-based PRAM/RTC, which
+ * is basically any machine with Mac II-style ADB.
+ */
+
+__u32 via_read_time(void)
+{
+	union {
+		__u8  cdata[4];
+		__u32 idata;
+	} result, last_result;
+	int	ct;
+
+	/*
+	 * The NetBSD guys say to loop until you get the same reading
+	 * twice in a row.
+	 */
+
+	ct = 0;
+	do {
+		if (++ct > 10) {
+			printk("via_read_time: couldn't get valid time, "
+			       "last read = 0x%08X and 0x%08X\n", last_result.idata,
+			       result.idata);
+			break;
+		}
+
+		last_result.idata = result.idata;
+		result.idata = 0;
+
+		via_pram_command(0x81, &result.cdata[3]);
+		via_pram_command(0x85, &result.cdata[2]);
+		via_pram_command(0x89, &result.cdata[1]);
+		via_pram_command(0x8D, &result.cdata[0]);
+	} while (result.idata != last_result.idata);
+
+	return result.idata;
+}
+
+/*
+ * Set the current time to a number of seconds since January 1, 1904.
+ *
+ * This only works on machines with the VIA-based PRAM/RTC, which
+ * is basically any machine with Mac II-style ADB.
+ */
+
+void via_write_time(__u32 time)
+{
+	union {
+		__u8  cdata[4];
+		__u32 idata;
+	} data;
+	__u8	temp;
+
+	/* Clear the write protect bit */
+
+	temp = 0x55;
+	via_pram_command(0x35, &temp);
+
+	data.idata = time;
+	via_pram_command(0x01, &data.cdata[3]);
+	via_pram_command(0x05, &data.cdata[2]);
+	via_pram_command(0x09, &data.cdata[1]);
+	via_pram_command(0x0D, &data.cdata[0]);
+
+	/* Set the write protect bit */
+
+	temp = 0xD5;
+	via_pram_command(0x35, &temp);
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c
--- v2.3.16/linux/arch/m68k/mac/via6522.c	Thu Dec 17 09:06:29 1998
+++ linux/arch/m68k/mac/via6522.c	Wed Dec 31 16:00:00 1969
@@ -1,419 +0,0 @@
-/*
- *	6522 Versatile Interface Adapter (VIA)
- *
- *	There are two of these on the Mac II. Some IRQ's are vectored
- *	via them as are assorted bits and bobs - eg rtc, adb.
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#include <asm/adb.h> 
-#include <asm/bootinfo.h> 
-#include <asm/macintosh.h> 
-#include <asm/macints.h> 
-#include "via6522.h"
-#include <asm/mac_psc.h>
-
-volatile unsigned char *via1=(unsigned char *)VIABASE;
-volatile unsigned char *via2=(unsigned char *)VIABASE2;
-volatile unsigned char *psc=(unsigned char *)PSCBASE;
-
-volatile long *via_memory_bogon=(long *)&via_memory_bogon;
-
-unsigned char via1_clock, via1_datab;
-
-static int rbv=0;
-static int oss=0;
-
-extern void adb_interrupt(int slot, void *via, struct pt_regs *regs);
-
-/*
- * hardware reset vector
- */
-static void (*rom_reset)(void);
-
-/*
- * Timer defs.
- */
-#define MAC_CLOCK_TICK		(783300/HZ)	/* ticks per HZ */
-#define MAC_CLOCK_LOW		(MAC_CLOCK_TICK&0xFF)
-#define MAC_CLOCK_HIGH		(MAC_CLOCK_TICK>>8)
-
-
-void via_configure_base(void)
-{
-
-	switch(macintosh_config->via_type)
-	{
-		/*
-		 *      CI, SI, VX, LC 
-		 */
-		case MAC_VIA_IIci:
-			via1=(void *)0x50F00000;
-			via2=(void *)0x50F26000;
-			rbv=1;
-			if (macintosh_config->ident == MAC_MODEL_IIFX) {
-				via2=(void *)0x50F1A000;
-				oss=1;
-			}
-			break;
-		/*
-		 *      Quadra and early MacIIs agree on the VIA locations
-		 */
-		case MAC_VIA_QUADRA:
-		case MAC_VIA_II:
-			via1=(void *)0x50F00000;
-			via2=(void *)0x50F02000;
-			break;
-		default:
-	}
-}
-
-
-void via_init_clock(void (*func)(int, void *, struct pt_regs *))
-{	
-	unsigned char c;
-	
-	via1_clock=via_read(via1, vACR);
-	via1_datab=via_read(via1, vBufB);
-
-	/*
-	 * Tell what MacOS left us with
-	 */
-
-	printk("via_init: boot via1 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n",
-		(int)via1_clock, (int)via_read(via1, vPCR), 
-		(int)via_read(via1, vBufA), (int)via_read(via1, vDirA),
-		(int)via_read(via1, vBufB), (int)via_read(via1, vDirB));
-
-	if (rbv == 0)
-		printk("via_init: boot via2 acr=%X pcr=%X buf_a=%X dir_a=%X buf_b=%X dir_b=%X \n",
-			(int)via_read(via2, vACR), (int)via_read(via2, vPCR), 
-			(int)via_read(via2, vBufA), (int)via_read(via2, vDirA),
-			(int)via_read(via2, vBufB), (int)via_read(via2, vDirB));
-
-	/*
-	 *	Shut it down
-	 */
-
-	via_write(via1,vIER, 0x7F);	 
-	
-	/*
-	 *	Kill the timers
-	 */
-	 
-	via_write(via1,vT1LL,0);
-	via_write(via1,vT1LH,0);
-	via_write(via1,vT1CL,0);
-	via_write(via1,vT1CH,0);
-	via_write(via1,vT2CL,0);
-	via_write(via1,vT2CH,0);
-	
-	/*
-	 *	Now do via2
-	 */
-
-	if(rbv==0) 
-	{
-		via_write(via2,vT1LL,0);
-		via_write(via2,vT1LH,0);
-		via_write(via2,vT1CL,0);
-		via_write(via2,vT1CH,0);
-		via_write(via2,vT2CL,0);
-		via_write(via2,vT2CH,0);
-		via_write(via2,vIER, 0x7F);	 
-	}
-	else if (oss==0)
-	{
-		/*
-		 *	Init the RBV chip a bit
-		 */
-		
-		via_write(via2, rIER,0x7F);
-	}
-
-	/*
-	 *	Disable the timer latches
-	 */
-	
-	c=via_read(via1,vACR);
-	via_write(via1,vACR,c&0x3F);
-
-	if(rbv==0) 
-	{
-		c=via_read(via2,vACR);
-		via_write(via2,vACR,c&0x3F);
-	}
-	  
-	/*
-	 *	Now start the clock - we want 100Hz
-	 */
-	 
-	via_write(via1,vACR,via_read(via1,vACR)|0x40);
-	
-	via_write(via1,vT1LL, MAC_CLOCK_LOW);
-	via_write(via1,vT1LH, MAC_CLOCK_HIGH);
-	via_write(via1,vT1CL, MAC_CLOCK_LOW);
-	via_write(via1,vT1CH, MAC_CLOCK_HIGH);
-	
-	/*
-	 *	And enable its interrupt
-	 */
-	
-	request_irq(IRQ_MAC_TIMER_1, func, IRQ_FLG_LOCK, "timer", func);
-
-	/* 
-	 * SE/30: disable video int. 
-	 * XXX: testing for SE/30 VBL
-	 */
-
-	if (macintosh_config->ident == MAC_MODEL_SE30) {
-		c = via_read(via1, vBufB);
-		via_write(via1, vBufB, c|(0x40));
-		c = via_read(via1, vDirB);
-		via_write(via1, vDirB, c|(0x40));
-	} 
-
-#if 0 /* gone to mac_init_IRQ */
-	/*
-	 * Set vPCR for SCSI interrupts.
-	 *
-	 * That is: CA1 negative edge int., CA2 indep., positive edge int.;
-	 *	    CB1 negative edge int., CB2 indep., positive edge int..
-	 */
-        via_write(via2,vPCR, 0x66);
-#endif                                                                  
-
-}
-
-/*
- * TBI: get time offset between scheduling timer ticks
- */
-#define TICK_SIZE 10000
-  
-/* This is always executed with interrupts disabled.  */
-
-unsigned long mac_gettimeoffset (void)
-{
-	unsigned long ticks, offset = 0;
-
-	/* read VIA1 timer 2 current value */
-	ticks = via_read(via1, vT1CL) + (via_read(via1, vT1CH)<<8);
-	/* The probability of underflow is less than 2% */
-	if (ticks > MAC_CLOCK_TICK - MAC_CLOCK_TICK / 50)
-		/* Check for pending timer interrupt in VIA1 IFR */
-		if (via_read(via1, vIFR) & 0x40)
-			offset = TICK_SIZE;
-
-	ticks = MAC_CLOCK_TICK - ticks;
-	ticks = ticks * 10000L / MAC_CLOCK_TICK;
-
-	return ticks + offset;
-}
-
-/*
- *	PSC (AV Macs; level 3-6): initialize interrupt enable registers
- */
-
-void psc_init(void)
-{
-	via_write(psc, pIER3, 0x01);
-	via_write(psc, pIER4, 0x09);
-	via_write(psc, pIER4, 0x86);
-	via_write(psc, pIER5, 0x03);
-	via_write(psc, pIER6, 0x07);
-}
-
-/*
- *	The power switch - yes it's software!
- */
-
-void mac_poweroff(void)
-{
-
-	/*
-	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
-	 * work using the ADB packet method.  --David Kilzer
-	 */
-
-	if (macintosh_config->adb_type == MAC_ADB_II)
-	{
-		if(rbv)	{
-			via_write(via2, rBufB, via_read(via2, rBufB)&~0x04);
-		} else {
-			/* Direction of vDirB is output */
-			via_write(via2,vDirB,via_read(via2,vDirB)|0x04);
-			/* Send a value of 0 on that line */
-			via_write(via2,vBufB,via_read(via2,vBufB)&~0x04);
-			/* Otherwise it prints "It is now.." then shuts off */
-			mdelay(1000);
-		}
-
-		/* We should never make it this far... */
-		printk ("It is now safe to switch off your machine.\n");
-
-		/* XXX - delay do we need to spin here ? */
-		while(1);	/* Just in case .. */
-	}
-
-	/*
-	 * Initially discovered this technique in the Mach kernel of MkLinux in
-	 * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c.  Found equivalent LinuxPPC
-	 * code in arch/ppc/kernel/setup.c, which also has a PMU technique for PowerBooks!
-	 * --David Kilzer
-	 */
-
-	else if (macintosh_config->adb_type == MAC_ADB_IISI
-	      || macintosh_config->adb_type == MAC_ADB_CUDA)
-	{
-		struct adb_request req;
-
-		/*
-		 * Print our "safe" message before we send the request
-		 * just in case the request never returns.
-		 */
-
-		printk ("It is now safe to switch off your machine.\n");
-
-		adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
-
-		printk ("ADB powerdown request sent.\n");
-		for (;;)
-		{
-			adb_poll();
-		}
-	}
-}
-
-/* 
- * Not all Macs support software power down; for the rest, just 
- * try the ROM reset vector ...
- */
-void mac_reset(void)
-{
-	/*
-	 * MAC_ADB_IISI may need to be moved up here if it doesn't actually
-	 * work using the ADB packet method.  --David Kilzer
-	 */
-
-	if (macintosh_config->adb_type == MAC_ADB_II)
-	{
-		unsigned long flags;
-		unsigned long *reset_hook;
-
-		/* need ROMBASE in booter */
-		/* indeed, plus need to MAP THE ROM !! */
-
-		if (mac_bi_data.rombase == 0)
-			mac_bi_data.rombase = 0x40800000;
-
-		/* works on some */
-		rom_reset = (void *) (mac_bi_data.rombase + 0xa);
-
-#if 0
-		/* testing, doesn't work on SE/30 either */
-		reset_hook = (unsigned long *) (mac_bi_data.rombase + 0x4);
-		printk("ROM reset hook: %p\n", *reset_hook);
-		rom_reset = *reset_hook;
-#endif
-		if (macintosh_config->ident == MAC_MODEL_SE30) {
-			/*
-			 * MSch: Machines known to crash on ROM reset ...
-			 */
-			printk("System halted.\n");
-			while(1);
-		} else {
-			save_flags(flags);
-			cli();
-
-			rom_reset();
-
-			restore_flags(flags);
-		}
-
-		/* We never make it this far... it usually panics above. */
-		printk ("Restart failed.  Please restart manually.\n");
-
-		/* XXX - delay do we need to spin here ? */
-		while(1);	/* Just in case .. */
-	}
-
-	/*
-	 * Initially discovered this technique in the Mach kernel of MkLinux in
-	 * osfmk/src/mach_kernel/ppc/POWERMAC/cuda_power.c.  Found equivalent LinuxPPC
-	 * code in arch/ppc/kernel/setup.c, which also has a PMU technique!
-	 * --David Kilzer
-	 * 
-	 * I suspect the MAC_ADB_CUDA code might work with other ADB types of machines
-	 * but have no way to test this myself.  --DDK
-	 */
-
-	else if (macintosh_config->adb_type == MAC_ADB_IISI
-	      || macintosh_config->adb_type == MAC_ADB_CUDA)
-	{
-		struct adb_request req;
-
-		adb_request (&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
-
-		printk ("Restart failed.  Please restart manually.\n");
-		for (;;)
-		{
-			adb_poll();
-		}
-	}
-}
-
-/*
- *	Set up the keyboard
- */
- 
-void via_setup_keyboard(void)
-{
-#if 0 /* moved to adb */
-	via1_func_tab.vector[2]=adb_interrupt;
-#else
-	request_irq(IRQ_MAC_ADB, adb_interrupt, IRQ_FLG_LOCK, "adb interrupt",
-		    adb_interrupt);
-#endif
-}
-
-/*
- *	Floppy hook
- */
-
-void via1_set_head(int head)
-{
-	if(head==0)
-		via_write(via1, vBufA, via_read(via1, vBufA)&~0x20);
-	else
-		via_write(via1, vBufA, via_read(via1, vBufA)|0x20);
-}
-
-void nubus_init_via(void)
-{
-	if (rbv) {
-		if (oss==0) {
-			via_write(via2, rBufB, via_read(via2, rBufB)|0x02);
-			via_write(via2, rIER, 0x82);	/* Interrupts on */
-		}
-	} else {
-		/* Assert the nubus active */
-		via_write(via2, vDirB, via_read(via2, vDirB)|0x02);
-		via_write(via2, vBufB, via_read(via2, vBufB)|0x02);
-		/* Make the nubus interrupt source register all output (disable) */
-		/* via_write(via2, vDirA, 0xFF); */
-		via_write(via2, vIER, 0x82);	/* Interrupts on */
-	}
-
-	printk("nubus_init_via: via1 acr=%X datab=%X pcr=%X\n",
-		(int)via_read(via1, vACR), (int)via_read(via1, vBufB), 
-		(int)via_read(via1, vPCR));
-
-	if (rbv==0)
-		printk("nubus_init_via: via2 acr=%X datab=%X pcr=%X\n",
-			(int)via_read(via2, vACR), (int)via_read(via2, vBufB), 
-			(int)via_read(via2, vPCR));
-}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mac/via6522.h linux/arch/m68k/mac/via6522.h
--- v2.3.16/linux/arch/m68k/mac/via6522.h	Mon Oct  5 13:54:39 1998
+++ linux/arch/m68k/mac/via6522.h	Wed Dec 31 16:00:00 1969
@@ -1,131 +0,0 @@
-/*
- *	6522 Versatile Interface Adapter (VIA)
- *
- *	There are two of these on the Mac II. Some IRQ's are vectored
- *	via them as are assorted bits and bobs - eg rtc, adb. The picture
- *	is a bit incomplete as the Mac documentation doesnt cover this well
- */
- 
-#ifndef _ASM_VIA6522_H_
-#define _ASM_VIA6522_H_
-
-#define VIABASE		0x50F00000
-#define VIABASE2	0x50F02000
-
-/*
- *	Not all of these are true post MacII I think
- */
- 
-#define VIA1A_vSccWrReq	0x80	/* SCC write */
-#define VIA1A_vRev8	0x40	/* Revision 8 board ??? */
-#define VIA1A_vHeadSel	0x20	/* Head select for IWM */
-#define VIA1A_vOverlay	0x10
-#define VIA1A_vSync	0x08
-#define VIA1A_vVolume	0x07	/* Audio volume mask */
-	
-#define VIA1B_vSound	0x80	/* Audio on/off */
-#define VIA1B_vMystery	0x40
-#define VIA1B_vADBS2	0x20	/* ADB state 2 */
-#define VIA1B_vADBS1	0x10	/* ADB state 1 */
-#define VIA1B_vADBInt	0x08	/* ADB interrupt */
-#define VIA1B_vRTCEnb	0x04	/* Real time clock */
-#define VIA1B_vRTCClk	0x02
-#define VIA1B_vRTCData	0x01
-
-/*
- *	VIA2 A register is the interrupt lines raised off the nubus 
- *	slots.
- */
- 
-#define VIA2A_vIRQE	0x20
-#define VIA2A_vIRQD	0x10
-#define VIA2A_vIRQC	0x08
-#define VIA2A_vIRQB	0x04
-#define VIA2A_vIRQA	0x02
-#define VIA2A_vIRQ9	0x01
-
-/*
- *	Register B has the fun stuff in it
- */
-
-#define VIA2B_vMode32	0x08	/* 24/32bit switch - doubles as cache flush */
-#define VIA2B_vPower	0x04	/* Off switch */
-#define VIA2B_vBusLk	0x02	/* Nubus in use ?? */
-#define VIA2B_vCDis	0x01	/* Cache disable */
-
-/*
- *	The 6522 via is a 2MHz part, and needs a delay. MacOS seems to
- *	execute MOV (Ax),(Ax) for this... Oh and we can't use udelay
- *	here... see we need the via to calibrate the udelay loop ...
- */
-
-extern volatile long *via_memory_bogon;
- 
-extern __inline__ void via_write(volatile unsigned char *via,int reg, int v)
-{
-	*via_memory_bogon;
-	*via_memory_bogon;
-	*via_memory_bogon;
-	via[reg]=v;
-}
-
-extern __inline__ int via_read(volatile unsigned char *via,int reg)
-{
-	*via_memory_bogon;
-	*via_memory_bogon;
-	*via_memory_bogon;
-	return (int)via[reg];
-}
-
-extern volatile unsigned char *via1,*via2;
-
-/*
- *	6522 registers - see databook
- */
- 
-#define vBufB	0x0000
-#define vBufA	0x0200
-#define vDirB	0x0400
-#define vDirA	0x0600
-#define vT1CL	0x0800
-#define vT1CH	0x0a00
-#define vT1LL	0x0c00
-#define vT1LH	0x0e00
-#define vT2CL	0x1000
-#define vT2CH	0x1200
-#define vSR	0x1400
-#define vACR	0x1600
-#define vPCR	0x1800
-#define vIFR	0x1a00
-#define vIER	0x1c00 
-#define vANH	0x1e00  /* register A (no shake) */
-
-#define rBufB	0x00
-#define rBufA	0x02
-/*#define rIFR	0x03*/
-#define rIFR	0x1A03
-#define rVideo	0x10
-#define rSlot	0x12
-/*#define rIER	0x13*/
-#define rIER	0x1C13
-/*
-#define R_rIFR	0x03
-#define R_rIER	0x13
-#define W_rIFR	0x1A03
-#define W_rIER	0x1C13
-*/
-/*
- *	VIA interrupt
- */
- 
-struct via_irq_tab
-{
-	void (*vector[8])(int, void *, struct pt_regs *);
-};
-
-extern void via1_irq(int, void *, struct pt_regs *);
-extern void via2_irq(int, void *, struct pt_regs *);
-
-extern void via_setup_keyboard(void);
-
-#endif /* _ASM_VIA6522_H_ */
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/math-emu/fp_entry.S linux/arch/m68k/math-emu/fp_entry.S
--- v2.3.16/linux/arch/m68k/math-emu/fp_entry.S	Tue Aug 17 10:39:02 1999
+++ linux/arch/m68k/math-emu/fp_entry.S	Sat Sep  4 13:06:41 1999
@@ -35,7 +35,6 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/entry.h>
 
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/math-emu/fp_util.S linux/arch/m68k/math-emu/fp_util.S
--- v2.3.16/linux/arch/m68k/math-emu/fp_util.S	Tue Aug 17 10:39:17 1999
+++ linux/arch/m68k/math-emu/fp_util.S	Sat Sep  4 13:06:41 1999
@@ -35,8 +35,6 @@
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/config.h>
-
 #include "fp_emu.h"
 
 /*
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/Makefile linux/arch/m68k/mm/Makefile
--- v2.3.16/linux/arch/m68k/mm/Makefile	Sat Jun 13 13:14:33 1998
+++ linux/arch/m68k/mm/Makefile	Sat Sep  4 13:06:41 1999
@@ -8,6 +8,13 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS	 := init.o fault.o memory.o kmap.o extable.o hwtest.o
+O_OBJS	 := init.o fault.o extable.o hwtest.o
+
+ifndef CONFIG_SUN3
+O_OBJS 	 += kmap.o memory.o motorola.o
+else
+O_OBJS	 += sun3mmu.o
+endif
+
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.3.16/linux/arch/m68k/mm/init.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/mm/init.c	Sat Sep  4 13:06:41 1999
@@ -2,6 +2,9 @@
  *  linux/arch/m68k/mm/init.c
  *
  *  Copyright (C) 1995  Hamish Macdonald
+ *
+ *  Contains common initialization routines, specific init code moved
+ *  to motorola.c and sun3mmu.c
  */
 
 #include <linux/config.h>
@@ -28,7 +31,10 @@
 #include <asm/atari_stram.h>
 #endif
 
-extern void die_if_kernel(char *,struct pt_regs *,long);
+#ifdef CONFIG_SUN3
+void mmu_emu_reserve_pages(unsigned long max_page);
+#endif
+
 extern void show_net_buffers(void);
 
 int do_check_pgt_cache(int low, int high)
@@ -58,7 +64,7 @@
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-static unsigned long empty_bad_page_table;
+unsigned long empty_bad_page_table;
 
 pte_t *__bad_pagetable(void)
 {
@@ -66,7 +72,7 @@
     return (pte_t *)empty_bad_page_table;
 }
 
-static unsigned long empty_bad_page;
+unsigned long empty_bad_page;
 
 pte_t __bad_page(void)
 {
@@ -111,169 +117,6 @@
 #endif
 }
 
-#ifndef mm_cachebits
-/*
- * Bits to add to page descriptors for "normal" caching mode.
- * For 68020/030 this is 0.
- * For 68040, this is _PAGE_CACHE040 (cachable, copyback)
- */
-unsigned long mm_cachebits = 0;
-#endif
-
-static pte_t * __init kernel_page_table(unsigned long *memavailp)
-{
-	pte_t *ptablep;
-
-	ptablep = (pte_t *)*memavailp;
-	*memavailp += PAGE_SIZE;
-
-	clear_page((unsigned long)ptablep);
-	flush_page_to_ram((unsigned long) ptablep);
-	flush_tlb_kernel_page((unsigned long) ptablep);
-	nocache_page ((unsigned long)ptablep);
-
-	return ptablep;
-}
-
-static pmd_t *last_pgtable __initdata = NULL;
-static pmd_t *zero_pgtable __initdata = NULL;
-
-static pmd_t * __init kernel_ptr_table(unsigned long *memavailp)
-{
-	if (!last_pgtable) {
-		unsigned long pmd, last;
-		int i;
-
-		/* Find the last ptr table that was used in head.S and
-		 * reuse the remaining space in that page for further
-		 * ptr tables.
-		 */
-		last = (unsigned long)kernel_pg_dir;
-		for (i = 0; i < PTRS_PER_PGD; i++) {
-			if (!pgd_present(kernel_pg_dir[i]))
-				continue;
-			pmd = pgd_page(kernel_pg_dir[i]);
-			if (pmd > last)
-				last = pmd;
-		}
-
-		last_pgtable = (pmd_t *)last;
-#ifdef DEBUG
-		printk("kernel_ptr_init: %p\n", last_pgtable);
-#endif
-	}
-
-	if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) {
-		last_pgtable = (pmd_t *)*memavailp;
-		*memavailp += PAGE_SIZE;
-
-		clear_page((unsigned long)last_pgtable);
-		flush_page_to_ram((unsigned long)last_pgtable);
-		flush_tlb_kernel_page((unsigned long)last_pgtable);
-		nocache_page((unsigned long)last_pgtable);
-	} else
-		last_pgtable += PTRS_PER_PMD;
-
-	return last_pgtable;
-}
-
-static unsigned long __init
-map_chunk (unsigned long addr, long size, unsigned long *memavailp)
-{
-#define PTRTREESIZE (256*1024)
-#define ROOTTREESIZE (32*1024*1024)
-	static unsigned long virtaddr = PAGE_OFFSET;
-	unsigned long physaddr;
-	pgd_t *pgd_dir;
-	pmd_t *pmd_dir;
-	pte_t *pte_dir;
-
-	physaddr = (addr | m68k_supervisor_cachemode |
-		    _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
-	if (CPU_IS_040_OR_060)
-		physaddr |= _PAGE_GLOBAL040;
-
-	while (size > 0) {
-#ifdef DEBUG
-		if (!(virtaddr & (PTRTREESIZE-1)))
-			printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
-				virtaddr);
-#endif
-		pgd_dir = pgd_offset_k(virtaddr);
-		if (virtaddr && CPU_IS_020_OR_030) {
-			if (!(virtaddr & (ROOTTREESIZE-1)) &&
-			    size >= ROOTTREESIZE) {
-#ifdef DEBUG
-				printk ("[very early term]");
-#endif
-				pgd_val(*pgd_dir) = physaddr;
-				size -= ROOTTREESIZE;
-				virtaddr += ROOTTREESIZE;
-				physaddr += ROOTTREESIZE;
-				continue;
-			}
-		}
-		if (!pgd_present(*pgd_dir)) {
-			pmd_dir = kernel_ptr_table(memavailp);
-#ifdef DEBUG
-			printk ("[new pointer %p]", pmd_dir);
-#endif
-			pgd_set(pgd_dir, pmd_dir);
-		} else
-			pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
-		if (CPU_IS_020_OR_030) {
-			if (virtaddr) {
-#ifdef DEBUG
-				printk ("[early term]");
-#endif
-				pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
-				physaddr += PTRTREESIZE;
-			} else {
-				int i;
-#ifdef DEBUG
-				printk ("[zero map]");
-#endif
-				zero_pgtable = kernel_ptr_table(memavailp);
-				pte_dir = (pte_t *)zero_pgtable;
-				pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
-					_PAGE_TABLE | _PAGE_ACCESSED;
-				pte_val(*pte_dir++) = 0;
-				physaddr += PAGE_SIZE;
-				for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
-					pte_val(*pte_dir++) = physaddr;
-			}
-			size -= PTRTREESIZE;
-			virtaddr += PTRTREESIZE;
-		} else {
-			if (!pmd_present(*pmd_dir)) {
-#ifdef DEBUG
-				printk ("[new table]");
-#endif
-				pte_dir = kernel_page_table(memavailp);
-				pmd_set(pmd_dir, pte_dir);
-			}
-			pte_dir = pte_offset(pmd_dir, virtaddr);
-
-			if (virtaddr) {
-				if (!pte_present(*pte_dir))
-					pte_val(*pte_dir) = physaddr;
-			} else
-				pte_val(*pte_dir) = 0;
-			size -= PAGE_SIZE;
-			virtaddr += PAGE_SIZE;
-			physaddr += PAGE_SIZE;
-		}
-
-	}
-#ifdef DEBUG
-	printk("\n");
-#endif
-
-	return virtaddr;
-}
-
-extern unsigned long free_area_init(unsigned long, unsigned long);
 extern void init_pointer_table(unsigned long ptable);
 
 /* References to section boundaries */
@@ -281,87 +124,7 @@
 extern char _text, _etext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
 
-/*
- * paging_init() continues the virtual memory environment setup which
- * was begun by the code in arch/head.S.
- */
-unsigned long __init paging_init(unsigned long start_mem,
-				     unsigned long end_mem)
-{
-	int chunk;
-	unsigned long mem_avail = 0;
-
-#ifdef DEBUG
-	{
-		extern unsigned long availmem;
-		printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
-			kernel_pg_dir, availmem, start_mem, end_mem);
-	}
-#endif
-
-	/* Fix the cache mode in the page descriptors for the 680[46]0.  */
-	if (CPU_IS_040_OR_060) {
-		int i;
-#ifndef mm_cachebits
-		mm_cachebits = _PAGE_CACHE040;
-#endif
-		for (i = 0; i < 16; i++)
-			pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
-	}
-	/* Fix the PAGE_NONE value. */
-	if (CPU_IS_040_OR_060) {
-		/* On the 680[46]0 we can use the _PAGE_SUPER bit.  */
-		pgprot_val(protection_map[0]) |= _PAGE_SUPER;
-		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER;
-	} else {
-		/* Otherwise we must fake it. */
-		pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT;
-		pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER;
-		pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT;
-		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER;
-	}
-
-	/*
-	 * Map the physical memory available into the kernel virtual
-	 * address space.  It may allocate some memory for page
-	 * tables and thus modify availmem.
-	 */
-
-	for (chunk = 0; chunk < m68k_num_memory; chunk++) {
-		mem_avail = map_chunk (m68k_memory[chunk].addr,
-				       m68k_memory[chunk].size, &start_mem);
-
-	}
-
-	flush_tlb_all();
-#ifdef DEBUG
-	printk ("memory available is %ldKB\n", mem_avail >> 10);
-	printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
-		start_mem, end_mem);
-#endif
-
-	/*
-	 * initialize the bad page table and bad page to point
-	 * to a couple of allocated pages
-	 */
-	empty_bad_page_table = start_mem;
-	start_mem += PAGE_SIZE;
-	empty_bad_page = start_mem;
-	start_mem += PAGE_SIZE;
-	empty_zero_page = start_mem;
-	start_mem += PAGE_SIZE;
-	memset((void *)empty_zero_page, 0, PAGE_SIZE);
-
-	/*
-	 * Set up SFC/DFC registers (user data space)
-	 */
-	set_fs (USER_DS);
-
-#ifdef DEBUG
-	printk ("before free_area_init\n");
-#endif
-	return PAGE_ALIGN(free_area_init(start_mem, end_mem));
-}
+extern pmd_t *zero_pgtable;
 
 void __init mem_init(unsigned long start_mem, unsigned long end_mem)
 {
@@ -386,18 +149,22 @@
 		atari_stram_reserve_pages( start_mem );
 #endif
 
+#ifdef CONFIG_SUN3
+	/* reserve rom pages */
+	mmu_emu_reserve_pages(max_mapnr);
+#endif
+
 	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
+#ifndef CONFIG_SUN3
 		if (virt_to_phys ((void *)tmp) >= mach_max_dma_address)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
+#endif
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
 			if (tmp >= (unsigned long)&_text
-			    && tmp < (unsigned long)&_edata) {
-				if (tmp < (unsigned long) &_etext)
-					codepages++;
-				else
-					datapages++;
-			} else if (tmp >= (unsigned long) &__init_begin
-				   && tmp < (unsigned long) &__init_end)
+			    && tmp < (unsigned long)&_etext)
+				codepages++;
+			else if (tmp >= (unsigned long) &__init_begin
+				 && tmp < (unsigned long) &__init_end)
 				initpages++;
 			else
 				datapages++;
@@ -410,7 +177,8 @@
 #endif
 			free_page(tmp);
 	}
-
+	
+#ifndef CONFIG_SUN3
 	/* insert pointer tables allocated so far into the tablelist */
 	init_pointer_table((unsigned long)kernel_pg_dir);
 	for (i = 0; i < PTRS_PER_PGD; i++) {
@@ -421,6 +189,7 @@
 	/* insert also pointer table that we used to unmap the zero page */
 	if (zero_pgtable)
 		init_pointer_table((unsigned long)zero_pgtable);
+#endif
 
 	printk("Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init)\n",
 	       (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
@@ -428,18 +197,6 @@
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10),
 	       initpages << (PAGE_SHIFT-10));
-}
-
-void free_initmem(void)
-{
-	unsigned long addr;
-
-	addr = (unsigned long)&__init_begin;
-	for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
-		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		set_page_count(mem_map+MAP_NR(addr), 1);
-		free_page(addr);
-	}
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.3.16/linux/arch/m68k/mm/memory.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/m68k/mm/memory.c	Sat Sep  4 13:06:41 1999
@@ -385,7 +385,7 @@
 }
 
 #ifndef CONFIG_SINGLE_MEMORY_CHUNK
-void *mm_ptov (unsigned long paddr)
+unsigned long mm_ptov (unsigned long paddr)
 {
 	int i = 0;
 	unsigned long poff, voff = PAGE_OFFSET;
@@ -396,7 +396,7 @@
 #ifdef DEBUGPV
 			printk ("PTOV(%lx)=%lx\n", paddr, poff + voff);
 #endif
-			return (void *)(poff + voff);
+			return poff + voff;
 		}
 		voff += m68k_memory[i].size;
 	} while (++i < m68k_num_memory);
@@ -429,9 +429,9 @@
 	 * to the ZTWO_VADDR range
 	 */
 	if (MACH_IS_AMIGA && paddr < 16*1024*1024)
-		return (void *)ZTWO_VADDR(paddr);
+		return ZTWO_VADDR(paddr);
 #endif
-	return (void *)-1;
+	return -1;
 }
 #endif
 
@@ -491,14 +491,7 @@
  * this?). So we have to push first and then additionally to invalidate.
  */
 
-#ifdef CONFIG_M68K_L2_CACHE
-/*
- *	Jes was worried about performance (urhh ???) so its optional
- */
- 
-void (*mach_l2_flush)(int) = NULL;
-#endif
- 
+
 /*
  * cache_clear() semantics: Clear any cache entries for the area in question,
  * without writing back dirty entries first. This is useful if the data will
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/motorola.c linux/arch/m68k/mm/motorola.c
--- v2.3.16/linux/arch/m68k/mm/motorola.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mm/motorola.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,299 @@
+/*
+ * linux/arch/m68k/motorola.c
+ *
+ * Routines specific to the Motorola MMU, originally from:
+ * linux/arch/m68k/init.c 
+ * which are Copyright (C) 1995 Hamish Macdonald
+ * 
+ * Moved 8/20/1999 Sam Creasey
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#ifdef CONFIG_ATARI
+#include <asm/atari_stram.h>
+#endif
+
+#undef DEBUG
+
+#ifndef mm_cachebits
+/*
+ * Bits to add to page descriptors for "normal" caching mode.
+ * For 68020/030 this is 0.
+ * For 68040, this is _PAGE_CACHE040 (cachable, copyback)
+ */
+unsigned long mm_cachebits = 0;
+#endif
+
+static pte_t * __init kernel_page_table(unsigned long *memavailp)
+{
+	pte_t *ptablep;
+
+	ptablep = (pte_t *)*memavailp;
+	*memavailp += PAGE_SIZE;
+
+	clear_page((unsigned long)ptablep);
+	flush_page_to_ram((unsigned long) ptablep);
+	flush_tlb_kernel_page((unsigned long) ptablep);
+	nocache_page ((unsigned long)ptablep);
+
+	return ptablep;
+}
+
+static pmd_t *last_pgtable __initdata = NULL;
+pmd_t *zero_pgtable __initdata = NULL;
+
+static pmd_t * __init kernel_ptr_table(unsigned long *memavailp)
+{
+	if (!last_pgtable) {
+		unsigned long pmd, last;
+		int i;
+
+		/* Find the last ptr table that was used in head.S and
+		 * reuse the remaining space in that page for further
+		 * ptr tables.
+		 */
+		last = (unsigned long)kernel_pg_dir;
+		for (i = 0; i < PTRS_PER_PGD; i++) {
+			if (!pgd_present(kernel_pg_dir[i]))
+				continue;
+			pmd = pgd_page(kernel_pg_dir[i]);
+			if (pmd > last)
+				last = pmd;
+		}
+
+		last_pgtable = (pmd_t *)last;
+#ifdef DEBUG
+		printk("kernel_ptr_init: %p\n", last_pgtable);
+#endif
+	}
+
+	if (((unsigned long)(last_pgtable + PTRS_PER_PMD) & ~PAGE_MASK) == 0) {
+		last_pgtable = (pmd_t *)*memavailp;
+		*memavailp += PAGE_SIZE;
+
+		clear_page((unsigned long)last_pgtable);
+		flush_page_to_ram((unsigned long)last_pgtable);
+		flush_tlb_kernel_page((unsigned long)last_pgtable);
+		nocache_page((unsigned long)last_pgtable);
+	} else
+		last_pgtable += PTRS_PER_PMD;
+
+	return last_pgtable;
+}
+
+static unsigned long __init 
+map_chunk (unsigned long addr, long size, unsigned long *memavailp)
+{
+#define PTRTREESIZE (256*1024)
+#define ROOTTREESIZE (32*1024*1024)
+	static unsigned long virtaddr = PAGE_OFFSET;
+	unsigned long physaddr;
+	pgd_t *pgd_dir;
+	pmd_t *pmd_dir;
+	pte_t *pte_dir;
+
+	physaddr = (addr | m68k_supervisor_cachemode |
+		    _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+	if (CPU_IS_040_OR_060)
+		physaddr |= _PAGE_GLOBAL040;
+
+	while (size > 0) {
+#ifdef DEBUG
+		if (!(virtaddr & (PTRTREESIZE-1)))
+			printk ("\npa=%#lx va=%#lx ", physaddr & PAGE_MASK,
+				virtaddr);
+#endif
+		pgd_dir = pgd_offset_k(virtaddr);
+		if (virtaddr && CPU_IS_020_OR_030) {
+			if (!(virtaddr & (ROOTTREESIZE-1)) &&
+			    size >= ROOTTREESIZE) {
+#ifdef DEBUG
+				printk ("[very early term]");
+#endif
+				pgd_val(*pgd_dir) = physaddr;
+				size -= ROOTTREESIZE;
+				virtaddr += ROOTTREESIZE;
+				physaddr += ROOTTREESIZE;
+				continue;
+			}
+		}
+		if (!pgd_present(*pgd_dir)) {
+			pmd_dir = kernel_ptr_table(memavailp);
+#ifdef DEBUG
+			printk ("[new pointer %p]", pmd_dir);
+#endif
+			pgd_set(pgd_dir, pmd_dir);
+		} else
+			pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+		if (CPU_IS_020_OR_030) {
+			if (virtaddr) {
+#ifdef DEBUG
+				printk ("[early term]");
+#endif
+				pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+				physaddr += PTRTREESIZE;
+			} else {
+				int i;
+#ifdef DEBUG
+				printk ("[zero map]");
+#endif
+				zero_pgtable = kernel_ptr_table(memavailp);
+				pte_dir = (pte_t *)zero_pgtable;
+				pmd_dir->pmd[0] = virt_to_phys(pte_dir) |
+					_PAGE_TABLE | _PAGE_ACCESSED;
+				pte_val(*pte_dir++) = 0;
+				physaddr += PAGE_SIZE;
+				for (i = 1; i < 64; physaddr += PAGE_SIZE, i++)
+					pte_val(*pte_dir++) = physaddr;
+			}
+			size -= PTRTREESIZE;
+			virtaddr += PTRTREESIZE;
+		} else {
+			if (!pmd_present(*pmd_dir)) {
+#ifdef DEBUG
+				printk ("[new table]");
+#endif
+				pte_dir = kernel_page_table(memavailp);
+				pmd_set(pmd_dir, pte_dir);
+			}
+			pte_dir = pte_offset(pmd_dir, virtaddr);
+
+			if (virtaddr) {
+				if (!pte_present(*pte_dir))
+					pte_val(*pte_dir) = physaddr;
+			} else
+				pte_val(*pte_dir) = 0;
+			size -= PAGE_SIZE;
+			virtaddr += PAGE_SIZE;
+			physaddr += PAGE_SIZE;
+		}
+
+	}
+#ifdef DEBUG
+	printk("\n");
+#endif
+
+	return virtaddr;
+}
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+extern unsigned long empty_bad_page_table;
+extern unsigned long empty_bad_page;
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ */
+unsigned long __init paging_init(unsigned long start_mem,
+				 unsigned long end_mem)
+{
+	int chunk;
+	unsigned long mem_avail = 0;
+
+#ifdef DEBUG
+	{
+		extern unsigned long availmem;
+		printk ("start of paging_init (%p, %lx, %lx, %lx)\n",
+			kernel_pg_dir, availmem, start_mem, end_mem);
+	}
+#endif
+
+	/* Fix the cache mode in the page descriptors for the 680[46]0.  */
+	if (CPU_IS_040_OR_060) {
+		int i;
+#ifndef mm_cachebits
+		mm_cachebits = _PAGE_CACHE040;
+#endif
+		for (i = 0; i < 16; i++)
+			pgprot_val(protection_map[i]) |= _PAGE_CACHE040;
+	}
+	/* Fix the PAGE_NONE value. */
+	if (CPU_IS_040_OR_060) {
+		/* On the 680[46]0 we can use the _PAGE_SUPER bit.  */
+		pgprot_val(protection_map[0]) |= _PAGE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_SUPER;
+	} else {
+		/* Otherwise we must fake it. */
+		pgprot_val(protection_map[0]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[0]) |= _PAGE_FAKE_SUPER;
+		pgprot_val(protection_map[VM_SHARED]) &= ~_PAGE_PRESENT;
+		pgprot_val(protection_map[VM_SHARED]) |= _PAGE_FAKE_SUPER;
+	}
+
+	/*
+	 * Map the physical memory available into the kernel virtual
+	 * address space.  It may allocate some memory for page
+	 * tables and thus modify availmem.
+	 */
+
+	for (chunk = 0; chunk < m68k_num_memory; chunk++) {
+		mem_avail = map_chunk (m68k_memory[chunk].addr,
+				       m68k_memory[chunk].size, &start_mem);
+
+	}
+
+	flush_tlb_all();
+#ifdef DEBUG
+	printk ("memory available is %ldKB\n", mem_avail >> 10);
+	printk ("start_mem is %#lx\nvirtual_end is %#lx\n",
+		start_mem, end_mem);
+#endif
+
+	/*
+	 * initialize the bad page table and bad page to point
+	 * to a couple of allocated pages
+	 */
+	empty_bad_page_table = start_mem;
+	start_mem += PAGE_SIZE;
+	empty_bad_page = start_mem;
+	start_mem += PAGE_SIZE;
+	empty_zero_page = start_mem;
+	start_mem += PAGE_SIZE;
+	memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+	/*
+	 * Set up SFC/DFC registers (user data space)
+	 */
+	set_fs (USER_DS);
+
+#ifdef DEBUG
+	printk ("before free_area_init\n");
+#endif
+	return PAGE_ALIGN(free_area_init(start_mem, end_mem));
+}
+
+extern char __init_begin, __init_end;
+
+void free_initmem(void)
+{
+	unsigned long addr;
+
+	addr = (unsigned long)&__init_begin;
+	for (; addr < (unsigned long)&__init_end; addr += PAGE_SIZE) {
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		set_page_count(mem_map+MAP_NR(addr), 1);
+		free_page(addr);
+	}
+}
+
+
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/mm/sun3mmu.c linux/arch/m68k/mm/sun3mmu.c
--- v2.3.16/linux/arch/m68k/mm/sun3mmu.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/mm/sun3mmu.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,98 @@
+/* 
+ * linux/arch/m68k/mm/sun3mmu.c
+ *
+ * Implementations of mm routines specific to the sun3 MMU.
+ *
+ * Moved here 8/20/1999 Sam Creasey
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#ifdef CONFIG_BLK_DEV_RAM
+#include <linux/blk.h>
+#endif
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+
+extern void mmu_emu_init (void);
+
+extern unsigned long free_area_init(unsigned long, unsigned long);
+
+const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
+
+extern unsigned long empty_bad_page_table;
+extern unsigned long empty_bad_page;
+
+void free_initmem(void)
+{
+}
+/* For the sun3 we try to follow the i386 paging_init() more closely */
+/* start_mem and end_mem have PAGE_OFFSET added already */
+/* now sets up tables using sun3 PTEs rather than i386 as before. --m */
+unsigned long __init paging_init(unsigned long start_mem,
+				 unsigned long end_mem)
+{
+	pgd_t * pg_dir;
+	pte_t * pg_table;
+	int i;
+	unsigned long address;
+
+#ifdef TEST_VERIFY_AREA
+	wp_works_ok = 0;
+#endif
+	start_mem = PAGE_ALIGN(start_mem);
+	empty_bad_page_table = start_mem;
+	start_mem += PAGE_SIZE;
+	empty_bad_page = start_mem;
+	start_mem += PAGE_SIZE;
+	empty_zero_page = start_mem;
+	start_mem += PAGE_SIZE;
+	memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+	address = PAGE_OFFSET;
+	pg_dir = swapper_pg_dir;
+	memset (swapper_pg_dir, 0, sizeof (swapper_pg_dir));
+	memset (kernel_pg_dir,  0, sizeof (kernel_pg_dir));
+
+	/* Map whole memory from PAGE_OFFSET (0x0E000000) */
+	pg_dir += PAGE_OFFSET >> PGDIR_SHIFT; 
+
+	while (address < end_mem) {
+		pg_table = (pte_t *) __pa (start_mem);
+		start_mem += PTRS_PER_PTE * sizeof (pte_t);
+		pgd_val(*pg_dir) = (unsigned long) pg_table;
+		pg_dir++;
+
+		/* now change pg_table to kernel virtual addresses */
+		pg_table = (pte_t *) __va ((unsigned long) pg_table);
+		for (i=0; i<PTRS_PER_PTE; ++i, ++pg_table) {
+			pte_t pte = mk_pte (address, PAGE_INIT);
+			if (address >= end_mem)
+				pte_val (pte) = 0;
+			set_pte (pg_table, pte);
+			address += PAGE_SIZE;
+		}
+	}
+
+	mmu_emu_init();
+	
+	current->mm = NULL;
+
+	return PAGE_ALIGN(free_area_init(start_mem, end_mem));
+}
+
+
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/Makefile linux/arch/m68k/sun3/Makefile
--- v2.3.16/linux/arch/m68k/sun3/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/Makefile	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,16 @@
+#
+# Makefile for Linux arch/m68k/sun3 source directory
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+	$(CC) -D__ASSEMBLY__ -traditional -Wa,-m68020 -c $< -o $*.o
+
+O_TARGET := sun3.o 
+O_OBJS   := config.o idprom.o mmu_emu.o sun3ints.o leds.o dvma.o sbus.o
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/config.c linux/arch/m68k/sun3/config.c
--- v2.3.16/linux/arch/m68k/sun3/config.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/config.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,173 @@
+/*
+ *  linux/arch/m68k/sun3/config.c
+ *
+ *  Copyright (C) 1996,1997 Pekka Pietik{inen
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <stdarg.h>
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/console.h>
+#include <linux/init.h>
+
+#include <asm/oplib.h>
+#include <asm/setup.h>
+#include <asm/contregs.h>
+#include <asm/movs.h>
+#include <asm/pgtable.h>
+#include <asm/sun3-head.h>
+#include <asm/sun3mmu.h>
+#include <asm/machdep.h>
+#include <asm/intersil.h>
+#include <asm/irq.h>
+#include <asm/segment.h>
+
+extern char _text, _end;
+
+static int kernel_start, kernel_end;
+char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
+
+static unsigned long sun3_gettimeoffset(void);
+extern int sun3_get_irq_list (char *);
+extern void sun3_sched_init(void (*handler)(int, void *, struct pt_regs *));
+extern void sun3_init_IRQ (void);
+extern void (*sun3_default_handler[]) (int, void *, struct pt_regs *);
+extern int sun3_request_irq (unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                              unsigned long flags, const char *devname, void *dev_id);
+extern void sun3_free_irq (unsigned int irq, void *dev_id);
+extern void sun3_enable_irq (unsigned int);
+extern void sun3_disable_irq (unsigned int);
+extern void sun3_enable_interrupts (void);
+extern void sun3_disable_interrupts (void);
+extern void sun3_get_model (unsigned char* model);
+extern void idprom_init (void);
+void sun3_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp);
+
+extern unsigned long sun_serial_setup(unsigned long memory_start);
+volatile char* clock_va; 
+extern unsigned char* sun3_intreg;
+
+__initfunc(void sun3_init(void))
+{
+	unsigned char enable_register;
+	int i;
+
+	m68k_machtype= MACH_SUN3;
+	m68k_cputype = CPU_68020;
+	m68k_fputype = FPU_68881; /* mc68881 actually */
+	m68k_mmutype = MMU_SUN3;
+	clock_va    =          (char *) 0xfe06000;	/* dark  */
+	sun3_intreg = (unsigned char *) 0xfe0a000;	/* magic */
+	sun3_disable_interrupts();
+	
+	prom_init((void *)LINUX_OPPROM_BEGVM);
+		
+	GET_CONTROL_BYTE(AC_SENABLE,enable_register);
+	enable_register |= 0x40; /* Enable FPU */	
+	SET_CONTROL_BYTE(AC_SENABLE,enable_register);
+	GET_CONTROL_BYTE(AC_SENABLE,enable_register);
+	
+	/* This code looks suspicious, because it doesn't subtract
+           memory belonging to the kernel from the available space */
+
+
+	memset(sun3_reserved_pmeg, 0, sizeof(sun3_reserved_pmeg));
+
+	/* Reserve important PMEGS */
+	/* FIXME: These should be probed instead of hardcoded */
+
+	for (i=0; i<8; i++)		/* Kernel PMEGs */
+		sun3_reserved_pmeg[i] = 1;
+
+	sun3_reserved_pmeg[247] = 1;	/* ROM mapping  */
+	sun3_reserved_pmeg[248] = 1;	/* AMD Ethernet */
+	sun3_reserved_pmeg[251] = 1;	/* VB area      */
+	sun3_reserved_pmeg[254] = 1;	/* main I/O     */
+
+	sun3_reserved_pmeg[249] = 1;
+	sun3_reserved_pmeg[252] = 1;
+	sun3_reserved_pmeg[253] = 1;
+	set_fs(KERNEL_DS);
+}
+
+/* Without this, Bad Things happen when something calls arch_reset. */
+static void sun3_reboot (void)
+{
+	prom_reboot ("vmlinux");
+}
+
+__initfunc(void config_sun3(unsigned long *start_mem_p, unsigned long *end_mem_p))
+{
+	printk("ARCH: SUN3\n");
+	idprom_init();
+
+	/* Subtract kernel memory from available memory */
+
+        mach_sched_init      =  sun3_sched_init; 
+        mach_init_IRQ        =  sun3_init_IRQ;
+        mach_default_handler = &sun3_default_handler;
+        mach_request_irq     =  sun3_request_irq;
+        mach_free_irq        =  sun3_free_irq;
+//	mach_keyb_init       =  sun3_keyb_init;
+	enable_irq     	     =  sun3_enable_irq;
+        disable_irq  	     =  sun3_disable_irq;
+        mach_get_irq_list    =  sun3_get_irq_list;
+        mach_gettod          =  sun3_gettod;	
+        mach_reset           =  sun3_reboot;
+	mach_gettimeoffset   =  sun3_gettimeoffset;
+	mach_get_model	     =  sun3_get_model;
+#ifndef CONFIG_SERIAL_CONSOLE
+	conswitchp 	     = &dummy_con;
+#endif
+	kernel_start = 0x00000000; /* NOT &_text */
+	kernel_end   = ((((int)&_end) + 0x2000) & ~0x1fff) - 1;
+
+	*start_mem_p = kernel_end + 1;
+// PROM seems to want the last couple of physical pages. --m
+	*end_mem_p   = *(romvec->pv_sun3mem) + PAGE_OFFSET - 2*PAGE_SIZE;
+	m68k_num_memory=1;
+        m68k_memory[0].size=*(romvec->pv_sun3mem);
+           
+        *start_mem_p = sun_serial_setup(*start_mem_p);
+}
+
+__initfunc(void sun3_sched_init(void (*timer_routine)(int, void *, struct pt_regs *)))
+{
+	sun3_disable_interrupts();
+        intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE);
+        intersil_clock->int_reg=INTERSIL_HZ_100_MASK;
+ 	intersil_clear();
+        sun3_enable_irq(5);
+        intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_ENABLE|INTERSIL_24H_MODE);
+        sun3_enable_interrupts();
+        intersil_clear();
+}
+
+static unsigned long sun3_gettimeoffset(void)
+{ 
+  return 1;
+}
+
+void sun3_gettod (int *yearp, int *monp, int *dayp,
+                   int *hourp, int *minp, int *secp)
+{
+	struct intersil_dt* todintersil;
+        todintersil = (struct intersil_dt *) &intersil_clock->counter;
+        *secp  = todintersil->second; 
+        *minp  = todintersil->minute;
+        *hourp = todintersil->hour;
+        *dayp  = todintersil->day;
+        *monp  = todintersil->month;
+        *yearp = todintersil->year+68; /* The base year for sun3 is 1968 */
+}
+
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/dvma.c linux/arch/m68k/sun3/dvma.c
--- v2.3.16/linux/arch/m68k/sun3/dvma.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/dvma.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,33 @@
+
+/* dvma support routines */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+
+unsigned long dvma_next_free = DVMA_START;
+
+/* get needed number of free dma pages, or panic if not enough */
+
+void *sun3_dvma_malloc(int len)
+{
+	unsigned long vaddr;
+	
+	/* if the next free pages have been accessed, skip them */
+	while((dvma_next_free < DVMA_END) &&
+	      (sun3_get_pte(dvma_next_free) & SUN3_PAGE_ACCESSED))
+		dvma_next_free += SUN3_PTE_SIZE;
+
+       	if((dvma_next_free + len) > DVMA_END) 
+		panic("sun3_dvma_malloc: out of dvma pages");
+	
+	vaddr = dvma_next_free;
+	dvma_next_free = PAGE_ALIGN(dvma_next_free + len);
+
+	return (void *)vaddr;
+}
+     
+
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/idprom.c linux/arch/m68k/sun3/idprom.c
--- v2.3.16/linux/arch/m68k/sun3/idprom.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/idprom.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,129 @@
+/* $Id: idprom.c,v 1.22 1996/11/13 05:09:25 davem Exp $
+ * idprom.c: Routines to load the idprom into kernel addresses and
+ *           interpret the data contained within.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/oplib.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>  /* Fun with Sun released architectures. */
+
+struct idprom *idprom;
+static struct idprom idprom_buffer;
+
+/* Here is the master table of Sun machines which use some implementation
+ * of the Sparc CPU and have a meaningful IDPROM machtype value that we
+ * know about.  See asm-sparc/machines.h for empirical constants.
+ */
+struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
+/* First, Sun3's */
+{ "Sun 3/160 Series", (SM_SUN3 | SM_3_160) },
+{ "Sun 3/50", (SM_SUN3 | SM_3_50) },
+{ "Sun 3/260 Series", (SM_SUN3 | SM_3_260) },
+{ "Sun 3/110 Series", (SM_SUN3 | SM_3_110) },
+{ "Sun 3/60", (SM_SUN3 | SM_3_60) },
+{ "Sun 3/E", (SM_SUN3 | SM_3_E) },
+/* Now, Sun3x's */
+{ "Sun 3/460 Series", (SM_SUN3 | SM_3_460) },
+{ "Sun 3/80", (SM_SUN3 | SM_3_80) },
+/* Then, Sun4's */
+//{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
+//{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
+//{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
+//{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+/* And now, Sun4c's */
+//{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
+//{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
+//{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
+//{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
+//{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
+//{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
+//{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
+/* Finally, early Sun4m's */
+//{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
+//{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) },
+//{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
+/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
+//{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) }
+};
+
+__initfunc(static void display_system_type(unsigned char machtype))
+{
+	register int i;
+
+	for (i = 0; i < NUM_SUN_MACHINES; i++) {
+		if(Sun_Machines[i].id_machtype == machtype) {
+			if (machtype != (SM_SUN4M_OBP | 0x00))
+				printk("TYPE: %s\n", Sun_Machines[i].name);
+			else {
+#if 0
+				prom_getproperty(prom_root_node, "banner-name",
+						 sysname, sizeof(sysname));
+				printk("TYPE: %s\n", sysname);
+#endif				
+			}
+			return;
+		}
+	}
+
+	prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
+	prom_halt();
+}
+
+void sun3_get_model(unsigned char* model)
+{
+	register int i;
+
+	for (i = 0; i < NUM_SUN_MACHINES; i++) {
+		if(Sun_Machines[i].id_machtype == idprom->id_machtype) {
+       		        strcpy(model, Sun_Machines[i].name);
+			return;
+		}
+	}
+}
+
+
+
+/* Calculate the IDPROM checksum (xor of the data bytes). */
+__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom))
+{
+	unsigned char cksum, i, *ptr = (unsigned char *)idprom;
+
+	for (i = cksum = 0; i <= 0x0E; i++)
+		cksum ^= *ptr++;
+
+	return cksum;
+}
+
+/* Create a local IDPROM copy, verify integrity, and display information. */
+__initfunc(void idprom_init(void))
+{
+	prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
+
+	idprom = &idprom_buffer;
+
+	if (idprom->id_format != 0x01)  {
+		prom_printf("IDPROM: Unknown format type!\n");
+		prom_halt();
+	}
+
+	if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
+		prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
+			    idprom->id_cksum, calc_idprom_cksum(idprom));
+		prom_halt();
+	}
+
+	display_system_type(idprom->id_machtype);
+
+	printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
+		    idprom->id_ethaddr[0], idprom->id_ethaddr[1],
+		    idprom->id_ethaddr[2], idprom->id_ethaddr[3],
+		    idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/leds.c linux/arch/m68k/sun3/leds.c
--- v2.3.16/linux/arch/m68k/sun3/leds.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/leds.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,16 @@
+#include <asm/contregs.h>
+#include <asm/sun3mmu.h>
+#include <asm/io.h>
+#include <asm/movs.h>
+
+#define FC_CONTROL 3    /* This should go somewhere else... */
+
+void sun3_leds(unsigned char byte)
+{
+	unsigned char dfc;
+	
+	GET_DFC(dfc);
+        SET_DFC(FC_CONTROL);
+       	SET_CONTROL_BYTE(AC_LEDS,byte);
+	SET_DFC(dfc);
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/mmu_emu.c linux/arch/m68k/sun3/mmu_emu.c
--- v2.3.16/linux/arch/m68k/sun3/mmu_emu.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/mmu_emu.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,445 @@
+/*
+** Tablewalk MMU emulator
+**
+** by Toshiyasu Morita
+**
+** Started 1/16/98 @ 2:22 am
+*/
+
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/delay.h>
+
+#include <asm/setup.h>
+#include <asm/traps.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sun3mmu.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+#include <asm/mmu_context.h>
+
+extern void prom_reboot (char *) __attribute__ ((__noreturn__));
+
+#undef DEBUG_MMU_EMU
+
+/*
+** Defines
+*/
+
+#define CONTEXTS_NUM		8
+#define SEGMAPS_PER_CONTEXT_NUM 2048
+#define PAGES_PER_SEGMENT	16
+#define PMEGS_NUM		256
+#define PMEG_MASK		0xFF
+
+/*
+** Globals
+*/
+
+unsigned long vmalloc_end = 0;
+unsigned long pmeg_vaddr[PMEGS_NUM];
+unsigned char pmeg_alloc[PMEGS_NUM];
+unsigned char pmeg_ctx[PMEGS_NUM];
+
+/* pointers to the mm structs for each task in each
+   context. 0xffffffff is a marker for kernel context */
+struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {0xffffffff, 0, 0, 0, 0, 0, 0, 0};
+/* has this context been mmdrop'd? */
+unsigned char ctx_live[CONTEXTS_NUM] = {1, 0, 0, 0, 0, 0, 0, 0};
+static unsigned char ctx_avail = CONTEXTS_NUM-1;
+unsigned char ctx_next_to_die = 1;
+
+/* array of pages to be marked off for the rom when we do mem_init later */
+/* 256 pages lets the rom take up to 2mb of physical ram..  I really
+   hope it never wants mote than that. */
+unsigned long rom_pages[256];
+
+/* Print a PTE value in symbolic form. For debugging. */
+void print_pte (pte_t pte)
+{
+#if 0
+	/* Verbose version. */
+	unsigned long val = pte_val (pte);
+	printk (" pte=%lx [addr=%lx",
+		val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT);
+	if (val & SUN3_PAGE_VALID)	printk (" valid");
+	if (val & SUN3_PAGE_WRITEABLE)	printk (" write");
+	if (val & SUN3_PAGE_SYSTEM)	printk (" sys");
+	if (val & SUN3_PAGE_NOCACHE)	printk (" nocache");
+	if (val & SUN3_PAGE_ACCESSED)	printk (" accessed");
+	if (val & SUN3_PAGE_MODIFIED)	printk (" modified");
+	switch (val & SUN3_PAGE_TYPE_MASK) {
+		case SUN3_PAGE_TYPE_MEMORY: printk (" memory"); break;
+		case SUN3_PAGE_TYPE_IO:     printk (" io");     break;
+		case SUN3_PAGE_TYPE_VME16:  printk (" vme16");  break;
+		case SUN3_PAGE_TYPE_VME32:  printk (" vme32");  break;
+	}
+	printk ("]\n");
+#else
+	/* Terse version. More likely to fit on a line. */
+	unsigned long val = pte_val (pte);
+	char flags[7], *type;
+
+	flags[0] = (val & SUN3_PAGE_VALID)     ? 'v' : '-';
+	flags[1] = (val & SUN3_PAGE_WRITEABLE) ? 'w' : '-';
+	flags[2] = (val & SUN3_PAGE_SYSTEM)    ? 's' : '-';
+	flags[3] = (val & SUN3_PAGE_NOCACHE)   ? 'x' : '-';
+	flags[4] = (val & SUN3_PAGE_ACCESSED)  ? 'a' : '-';
+	flags[5] = (val & SUN3_PAGE_MODIFIED)  ? 'm' : '-';
+	flags[6] = '\0';
+
+	switch (val & SUN3_PAGE_TYPE_MASK) {
+		case SUN3_PAGE_TYPE_MEMORY: type = "memory"; break;
+		case SUN3_PAGE_TYPE_IO:     type = "io"    ; break;
+		case SUN3_PAGE_TYPE_VME16:  type = "vme16" ; break;
+		case SUN3_PAGE_TYPE_VME32:  type = "vme32" ; break;
+		default: type = "unknown?"; break;
+	}
+
+	printk (" pte=%08lx [%07lx %s %s]\n",
+		val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT, flags, type);
+#endif
+}
+
+/* Print the PTE value for a given virtual address. For debugging. */
+void print_pte_vaddr (unsigned long vaddr)
+{
+	printk (" vaddr=%lx [%02lx]", vaddr, sun3_get_segmap (vaddr));
+	print_pte (__pte (sun3_get_pte (vaddr)));
+}
+
+/*
+ * Initialise the MMU emulator.
+ */
+void mmu_emu_init(void)
+{
+	unsigned long seg, num;
+	int i,j;
+	extern char _stext, _etext;
+	unsigned long page;
+
+	memset(rom_pages, 0, sizeof(rom_pages));
+	memset(pmeg_vaddr, 0, sizeof(pmeg_vaddr));
+	memset(pmeg_alloc, 0, sizeof(pmeg_alloc));
+	memset(pmeg_ctx, 0, sizeof(pmeg_ctx));
+
+#ifdef DEBUG_MMU_EMU
+	printk ("mmu_emu_init: stext=%p etext=%p pmegs=%u\n", &_stext,
+		&_etext, (&_etext-&_stext+SUN3_PMEG_SIZE-1) >>
+		SUN3_PMEG_SIZE_BITS); 
+#endif
+
+	/* mark the pmegs copied in sun3-head.S as used */
+	for (i=0; i<10; ++i)
+		pmeg_alloc[i] = 2;
+
+	/* I'm thinking that most of the top pmeg's are going to be
+	   used for something, and we probably shouldn't risk it */
+	for(num = 0xf0; num <= 0xff; num++)
+		pmeg_alloc[num] = 2;
+
+	j = 0;
+	for (num=0, seg=0x0F800000; seg<0x10000000; seg+=16*PAGE_SIZE) {
+		if (sun3_get_segmap (seg) != SUN3_INVALID_PMEG) {
+#ifdef DEBUG_MMU_EMU
+			printk ("mapped:");
+			print_pte_vaddr (seg);
+#endif
+			// the lowest mapping here is the end of our
+			// vmalloc region
+			if(!vmalloc_end)
+				vmalloc_end = seg;
+
+			// mark the segmap alloc'd, and reserve any
+			// of the first 0xbff pages the hardware is
+			// already using...  does any sun3 support > 24mb?
+			pmeg_alloc[sun3_get_segmap(seg)] = 2;
+			for(i = 0; i < SUN3_PMEG_SIZE; i += PAGE_SIZE)
+			{
+				page = (sun3_get_pte(seg+i) &
+					SUN3_PAGE_PGNUM_MASK);
+
+				if((page) && (page < 0xbff)) {
+					rom_pages[j] = page;
+					j++;
+				}
+			}
+		}
+	}
+
+	
+	/* blank everything below the kernel, and we've got the base
+	   mapping to start all the contexts off with... */
+	for(seg = 0; seg < PAGE_OFFSET; seg += SUN3_PMEG_SIZE) 
+		sun3_put_segmap(seg, SUN3_INVALID_PMEG);
+
+	set_fs(MAKE_MM_SEG(3));
+	for(seg = 0; seg < 0x10000000; seg += SUN3_PMEG_SIZE) {
+		i = sun3_get_segmap(seg);
+		for(j = 1; j < CONTEXTS_NUM; j++)
+			(*(romvec->pv_setctxt))(j, (void *)seg, i);
+	}
+	set_fs(KERNEL_DS);
+	
+}
+
+/* called during mem_init to create the needed holes in the mem
+   mappings */
+void mmu_emu_reserve_pages(unsigned long max_page)
+{
+	int i = 0;
+	
+	while(rom_pages[i] != 0) {
+		// don't tamper with pages that wound up after end_mem
+		if(rom_pages[i] < max_page) 
+			set_bit(PG_reserved, &mem_map[rom_pages[i]].flags);
+	     i++;
+	}
+}
+
+/* erase the mappings for a dead context.  Uses the pg_dir for hints
+   as the pmeg tables proved somewhat unreliable, and unmapping all of
+   TASK_SIZE was much slower and no more stable. */
+/* todo: find a better way to keep track of the pmegs used by a
+   context for when they're cleared */
+void clear_context(unsigned long context)
+{
+     unsigned char oldctx;
+     unsigned long i;
+    
+     if(!ctx_alloc[context])
+	     panic("clear_context: context not allocated\n");
+
+     oldctx = sun3_get_context();
+
+     sun3_put_context(context);
+
+     /* ctx_live denotes if we're clearing a context with an active
+	mm, in which case we can use the pgd for clues and also should
+	mark that mm as lacking a context.  if the context has been
+	mmdrop'd, then flush outright. */
+
+     if(!ctx_live[context]) {
+	     for(i = 0; i < TASK_SIZE ; i += SUN3_PMEG_SIZE) 
+		     sun3_put_segmap(i, SUN3_INVALID_PMEG);
+     } else {
+	     pgd_t *pgd;
+	     
+	     pgd = ctx_alloc[context]->pgd;
+	     ctx_alloc[context]->context = SUN3_INVALID_CONTEXT;
+	     for(i = 0; i < (TASK_SIZE>>PGDIR_SHIFT); i++, pgd++)
+	     {
+		     if(pgd_val(*pgd)) {
+			     sun3_put_segmap(i<<PGDIR_SHIFT,
+					     SUN3_INVALID_PMEG);
+		     }
+	     }
+     }
+     
+     for(i = 0; i < SUN3_INVALID_PMEG; i++) {
+	     if((pmeg_ctx[i] == context) && (pmeg_alloc[i] != 2)) {
+		     pmeg_ctx[i] = 0;
+		     pmeg_alloc[i] = 0;
+		     pmeg_vaddr[i] = 0;
+	     }
+     }
+     
+     ctx_alloc[context] = (struct mm_struct *)0;
+     ctx_avail++;
+}
+
+/* gets an empty context.  if full, kills the next context listed to
+   die first */
+/* This context invalidation scheme is, well, totally arbitrary, I'm
+   sure it could be much more intellegent...  but it gets the job done
+   for now without much overhead in making it's decision. */
+/* todo: come up with optimized scheme for flushing contexts */
+unsigned long get_free_context(struct mm_struct *mm) 
+{
+	unsigned long new = 1;
+
+	if(!ctx_avail) {
+		/* kill someone to get our context */
+		new = ctx_next_to_die;
+		clear_context(new);
+		ctx_next_to_die = (ctx_next_to_die + 1) & 0x7;
+		if(!ctx_next_to_die)
+			ctx_next_to_die++;
+	} else {
+		while(new < CONTEXTS_NUM) {
+			if(ctx_alloc[new])
+				new++;
+			else
+				break;
+		}
+		// check to make sure one was really free...
+		if(new == CONTEXTS_NUM) 
+			panic("get_free_context: failed to find free context");
+	}
+
+	ctx_alloc[new] = mm;
+	ctx_live[new] = 1;
+	ctx_avail--;
+
+	return new;
+}
+
+/*
+ * Dynamically select a `spare' PMEG and use it to map virtual `vaddr' in
+ * `context'. Maintain internal PMEG management structures. This doesn't
+ * actually map the physical address, but does clear the old mappings.
+ */
+//todo: better allocation scheme? but is extra complexity worthwhile?
+//todo: only clear old entries if necessary? how to tell?
+
+static inline void mmu_emu_map_pmeg (int context, int vaddr)
+{
+	static unsigned char curr_pmeg = 128;
+	int i;
+
+	/* Round address to PMEG boundary. */
+	vaddr &= ~SUN3_PMEG_MASK;
+
+	/* Find a spare one. */
+	while (pmeg_alloc[curr_pmeg] == 2)
+		++curr_pmeg;
+
+
+#ifdef DEBUG_MMU_EMU
+printk("mmu_emu_map_pmeg: pmeg %x to context %d vaddr %x\n",
+       curr_pmeg, context, vaddr);
+#endif
+
+	/* Invalidate old mapping for the pmeg, if any */
+	if (pmeg_alloc[curr_pmeg] == 1) {
+		sun3_put_context(pmeg_ctx[curr_pmeg]);
+		sun3_put_segmap (pmeg_vaddr[curr_pmeg], SUN3_INVALID_PMEG);
+		sun3_put_context(context);
+	}
+
+	/* Update PMEG management structures. */
+	// don't take pmeg's away from the kernel...
+	if(vaddr >= PAGE_OFFSET) {
+		/* map kernel pmegs into all contexts */
+		unsigned char i;
+		
+		for(i = 0; i < CONTEXTS_NUM; i++) {
+			sun3_put_context(i);
+			sun3_put_segmap (vaddr, curr_pmeg);
+		}
+		sun3_put_context(context);
+		pmeg_alloc[curr_pmeg] = 2;
+		pmeg_ctx[curr_pmeg] = 0;
+		
+	}
+	else {
+		pmeg_alloc[curr_pmeg] = 1;
+		pmeg_ctx[curr_pmeg] = context;
+		sun3_put_segmap (vaddr, curr_pmeg);
+
+	}
+	pmeg_vaddr[curr_pmeg] = vaddr;
+
+	/* Set hardware mapping and clear the old PTE entries. */
+	for (i=0; i<SUN3_PMEG_SIZE; i+=SUN3_PTE_SIZE) 
+		sun3_put_pte (vaddr + i, SUN3_PAGE_SYSTEM);
+
+	/* Consider a different one next time. */
+	++curr_pmeg;
+}
+
+/*
+ * Handle a pagefault at virtual address `vaddr'; check if there should be a
+ * page there (specifically, whether the software pagetables indicate that
+ * there is). This is necessary due to the limited size of the second-level
+ * Sun3 hardware pagetables (256 groups of 16 pages). If there should be a
+ * mapping present, we select a `spare' PMEG and use it to create a mapping.
+ * `read_flag' is nonzero for a read fault; zero for a write. Returns nonzero
+ * if we successfully handled the fault.
+ */
+//todo: should we bump minor pagefault counter? if so, here or in caller?
+//todo: possibly inline this into bus_error030 in <asm/buserror.h> ?
+
+// kernel_fault is set when a kernel page couldn't be demand mapped,
+// and forces another try using the kernel page table.  basically a
+// hack so that vmalloc would work correctly.
+
+int mmu_emu_handle_fault (unsigned long vaddr, int read_flag, int kernel_fault)
+{
+	unsigned long segment, offset;
+	unsigned char context;
+	pte_t *pte;
+	pgd_t * crp;
+
+	if(current->mm == NULL) {
+		crp = swapper_pg_dir;
+		context = 0;
+	} else {
+		context = current->mm->context;
+		if(kernel_fault) 
+			crp = swapper_pg_dir;
+		else
+			crp = current->mm->pgd;
+	}
+
+#ifdef DEBUG_MMU_EMU
+	printk ("mmu_emu_handle_fault: vaddr=%lx type=%s crp=%p\n",
+		vaddr, read_flag ? "read" : "write", crp);
+#endif
+
+	segment = (vaddr >> SUN3_PMEG_SIZE_BITS) & 0x7FF;
+	offset  = (vaddr >> SUN3_PTE_SIZE_BITS) & 0xF;
+
+#ifdef DEBUG_MMU_EMU
+	printk ("mmu_emu_handle_fault: segment=%lx offset=%lx\n", segment, offset);
+#endif
+
+	pte = (pte_t *) pgd_val (*(crp + segment));
+
+//todo: next line should check for valid pmd properly.
+	if (!pte) {
+//                printk ("mmu_emu_handle_fault: invalid pmd\n");
+                return 0;
+        }
+
+	pte = (pte_t *) __va ((unsigned long)(pte + offset));
+
+	/* Make sure this is a valid page */
+	if (!(pte_val (*pte) & SUN3_PAGE_VALID)) 
+		return 0;
+
+	/* Make sure there's a pmeg allocated for the page */
+	if (sun3_get_segmap (vaddr&~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG) 
+		mmu_emu_map_pmeg (context, vaddr);
+
+	/* Write the pte value to hardware MMU */
+	sun3_put_pte (vaddr&PAGE_MASK, pte_val (*pte));
+
+	/* Update software copy of the pte value */
+// I'm not sure this is necessary. If this is required, we ought to simply
+// copy this out when we reuse the PMEG or at some other convenient time.
+// Doing it here is fairly meaningless, anyway, as we only know about the
+// first access to a given page. --m
+	if (!read_flag) {
+		if (pte_val (*pte) & SUN3_PAGE_WRITEABLE)
+			pte_val (*pte) |= (SUN3_PAGE_ACCESSED
+					   | SUN3_PAGE_MODIFIED);
+		else 
+			return 0;	/* Write-protect error. */
+	} else
+		pte_val (*pte) |= SUN3_PAGE_ACCESSED;
+
+#ifdef DEBUG_MMU_EMU
+	printk ("seg:%d crp:%p ->", get_fs().seg, crp);
+	print_pte_vaddr (vaddr);
+	printk ("\n");
+#endif
+
+	return 1;
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/Makefile linux/arch/m68k/sun3/prom/Makefile
--- v2.3.16/linux/arch/m68k/sun3/prom/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/prom/Makefile	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,22 @@
+# $Id: Makefile,v 1.5 1995/11/25 00:59:48 davem Exp $
+# Makefile for the Sun Boot PROM interface library under
+# Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+OBJS  = init.o console.o printf.o  misc.o
+#bootstr.o init.o misc.o segment.o console.o printf.o
+all: promlib.a
+
+promlib.a: $(OBJS)
+	$(AR) rcs promlib.a $(OBJS)
+	sync
+
+dep:
+	$(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/console.c linux/arch/m68k/sun3/prom/console.c
--- v2.3.16/linux/arch/m68k/sun3/prom/console.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/prom/console.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,175 @@
+/* $Id: console.c,v 1.10 1996/12/18 06:46:54 tridge Exp $
+ * console.c: Routines that deal with sending and receiving IO
+ *            to/from the current console device using the PROM.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <linux/string.h>
+
+/* Non blocking get character from console input device, returns -1
+ * if no input was taken.  This can be used for polling.
+ */
+int
+prom_nbgetchar(void)
+{
+	int i = -1;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+		i = (*(romvec->pv_nbgetchar))();
+	restore_flags(flags);
+	return i; /* Ugh, we could spin forever on unsupported proms ;( */
+}
+
+/* Non blocking put character to console device, returns -1 if
+ * unsuccessful.
+ */
+int
+prom_nbputchar(char c)
+{
+	unsigned long flags;
+	int i = -1;
+
+	save_flags(flags); cli();
+		i = (*(romvec->pv_nbputchar))(c);
+	restore_flags(flags);	
+	return i; /* Ugh, we could spin forever on unsupported proms ;( */
+}
+
+/* Blocking version of get character routine above. */
+char
+prom_getchar(void)
+{
+	int character;
+	while((character = prom_nbgetchar()) == -1) ;
+	return (char) character;
+}
+
+/* Blocking version of put character routine above. */
+void
+prom_putchar(char c)
+{
+	while(prom_nbputchar(c) == -1) ;
+	return;
+}
+
+/* Query for input device type */
+#if 0
+enum prom_input_device
+prom_query_input_device()
+{
+	unsigned long flags;
+	int st_p;
+	char propb[64];
+	char *p;
+
+	switch(prom_vers) {
+	case PROM_V0:
+	case PROM_V2:
+	default:
+		switch(*romvec->pv_stdin) {
+		case PROMDEV_KBD:	return PROMDEV_IKBD;
+		case PROMDEV_TTYA:	return PROMDEV_ITTYA;
+		case PROMDEV_TTYB:	return PROMDEV_ITTYB;
+		default:
+			return PROMDEV_I_UNK;
+		};
+	case PROM_V3:
+	case PROM_P1275:
+		save_flags(flags); cli();
+		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
+		__asm__ __volatile__("ld [%0], %%g6\n\t" : :
+				     "r" (&current_set[smp_processor_id()]) :
+				     "memory");
+		restore_flags(flags);
+		if(prom_node_has_property(st_p, "keyboard"))
+			return PROMDEV_IKBD;
+		prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+		if(strncmp(propb, "serial", sizeof("serial")))
+			return PROMDEV_I_UNK;
+		prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
+		p = propb;
+		while(*p) p++; p -= 2;
+		if(p[0] == ':') {
+			if(p[1] == 'a')
+				return PROMDEV_ITTYA;
+			else if(p[1] == 'b')
+				return PROMDEV_ITTYB;
+		}
+		return PROMDEV_I_UNK;
+	case PROM_AP1000:
+		return PROMDEV_I_UNK;
+	};
+}
+#endif
+
+/* Query for output device type */
+
+#if 0
+enum prom_output_device
+prom_query_output_device()
+{
+	unsigned long flags;
+	int st_p;
+	char propb[64];
+	char *p;
+	int propl;
+
+	switch(prom_vers) {
+	case PROM_V0:
+		switch(*romvec->pv_stdin) {
+		case PROMDEV_SCREEN:	return PROMDEV_OSCREEN;
+		case PROMDEV_TTYA:	return PROMDEV_OTTYA;
+		case PROMDEV_TTYB:	return PROMDEV_OTTYB;
+		};
+		break;
+	case PROM_V2:
+	case PROM_V3:
+	case PROM_P1275:
+		save_flags(flags); cli();
+		st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
+		__asm__ __volatile__("ld [%0], %%g6\n\t" : :
+				     "r" (&current_set[smp_processor_id()]) :
+				     "memory");
+		restore_flags(flags);
+		propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+		if (propl >= 0 && propl == sizeof("display") &&
+			strncmp("display", propb, sizeof("display")) == 0)
+		{
+			return PROMDEV_OSCREEN;
+		}
+		if(prom_vers == PROM_V3) {
+			if(strncmp("serial", propb, sizeof("serial")))
+				return PROMDEV_O_UNK;
+			prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb));
+			p = propb;
+			while(*p) p++; p -= 2;
+			if(p[0]==':') {
+				if(p[1] == 'a')
+					return PROMDEV_OTTYA;
+				else if(p[1] == 'b')
+					return PROMDEV_OTTYB;
+			}
+			return PROMDEV_O_UNK;
+		} else {
+			/* This works on SS-2 (an early OpenFirmware) still. */
+			switch(*romvec->pv_stdin) {
+			case PROMDEV_TTYA:	return PROMDEV_OTTYA;
+			case PROMDEV_TTYB:	return PROMDEV_OTTYB;
+			};
+		}
+		break;
+	case PROM_AP1000:
+		return PROMDEV_I_UNK;
+	};
+	return PROMDEV_O_UNK;
+}
+#endif
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/init.c linux/arch/m68k/sun3/prom/init.c
--- v2.3.16/linux/arch/m68k/sun3/prom/init.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/prom/init.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,89 @@
+/* $Id: init.c,v 1.9 1996/12/18 06:46:55 tridge Exp $
+ * init.c:  Initialize internal variables used by the PROM
+ *          library functions.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+struct linux_romvec *romvec;
+enum prom_major_version prom_vers;
+unsigned int prom_rev, prom_prev;
+
+/* The root node of the prom device tree. */
+int prom_root_node;
+
+/* Pointer to the device tree operations structure. */
+struct linux_nodeops *prom_nodeops;
+
+/* You must call prom_init() before you attempt to use any of the
+ * routines in the prom library.  It returns 0 on success, 1 on
+ * failure.  It gets passed the pointer to the PROM vector.
+ */
+
+extern void prom_meminit(void);
+extern void prom_ranges_init(void);
+
+__initfunc(void prom_init(struct linux_romvec *rp))
+{
+#if CONFIG_AP1000
+	extern struct linux_romvec *ap_prom_init(void);
+	rp = ap_prom_init();
+#endif
+
+	romvec = rp;
+#ifndef CONFIG_SUN3
+	switch(romvec->pv_romvers) {
+	case 0:
+		prom_vers = PROM_V0;
+		break;
+	case 2:
+		prom_vers = PROM_V2;
+		break;
+	case 3:
+		prom_vers = PROM_V3;
+		break;
+	case 4:
+		prom_vers = PROM_P1275;
+		prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
+		prom_halt();
+		break;
+	case 42: /* why not :-) */
+		prom_vers = PROM_AP1000;
+		break;
+
+	default:
+		prom_printf("PROMLIB: Bad PROM version %d\n",
+			    romvec->pv_romvers);
+		prom_halt();
+		break;
+	};
+
+	prom_rev = romvec->pv_plugin_revision;
+	prom_prev = romvec->pv_printrev;
+	prom_nodeops = romvec->pv_nodeops;
+
+	prom_root_node = prom_getsibling(0);
+	if((prom_root_node == 0) || (prom_root_node == -1))
+		prom_halt();
+
+	if((((unsigned long) prom_nodeops) == 0) || 
+	   (((unsigned long) prom_nodeops) == -1))
+		prom_halt();
+
+	prom_meminit();
+
+	prom_ranges_init();
+#endif
+//	printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
+//	       romvec->pv_romvers, prom_rev);
+
+	/* Initialization successful. */
+	return;
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/misc.c linux/arch/m68k/sun3/prom/misc.c
--- v2.3.16/linux/arch/m68k/sun3/prom/misc.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/prom/misc.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,95 @@
+/* $Id: misc.c,v 1.15 1997/05/14 20:45:00 davem Exp $
+ * misc.c:  Miscellaneous prom functions that don't belong
+ *          anywhere else.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/sun3-head.h>
+#include <asm/idprom.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/movs.h>
+
+/* Reset and reboot the machine with the command 'bcommand'. */
+void
+prom_reboot(char *bcommand)
+{
+	unsigned long flags;
+	save_flags(flags); cli();
+	(*(romvec->pv_reboot))(bcommand);
+	restore_flags(flags);
+}
+
+/* Drop into the prom, with the chance to continue with the 'go'
+ * prom command.
+ */
+void
+prom_cmdline(void)
+{
+}
+
+/* Drop into the prom, but completely terminate the program.
+ * No chance of continuing.
+ */
+void
+prom_halt(void)
+{
+	unsigned long flags;
+again:
+	save_flags(flags); cli();
+	(*(romvec->pv_halt))();
+	restore_flags(flags);
+	goto again; /* PROM is out to get me -DaveM */
+}
+
+typedef void (*sfunc_t)(void);
+
+/* Get the idprom and stuff it into buffer 'idbuf'.  Returns the
+ * format type.  'num_bytes' is the number of bytes that your idbuf
+ * has space for.  Returns 0xff on error.
+ */
+unsigned char
+prom_get_idprom(char *idbuf, int num_bytes)
+{
+	int i, oldsfc;
+	GET_SFC(oldsfc);
+	SET_SFC(FC_CONTROL);
+	for(i=0;i<num_bytes; i++)
+	{
+		/* There is a problem with the GET_CONTROL_BYTE
+		macro; defining the extra variable
+		gets around it.
+		*/
+		int c;
+		GET_CONTROL_BYTE(SUN3_IDPROM_BASE + i, c);
+		idbuf[i] = c;
+	}
+	SET_SFC(oldsfc);
+	return idbuf[0];
+}
+
+/* Get the major prom version number. */
+int
+prom_version(void)
+{
+	return romvec->pv_romvers;
+}
+
+/* Get the prom plugin-revision. */
+int
+prom_getrev(void)
+{
+	return prom_rev;
+}
+
+/* Get the prom firmware print revision. */
+int
+prom_getprev(void)
+{
+	return prom_prev;
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/prom/printf.c linux/arch/m68k/sun3/prom/printf.c
--- v2.3.16/linux/arch/m68k/sun3/prom/printf.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/prom/printf.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,61 @@
+/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $
+ * printf.c:  Internal prom library printf facility.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* This routine is internal to the prom library, no one else should know
+ * about or use it!  It's simple and smelly anyway....
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+
+#ifdef CONFIG_KGDB
+extern int kgdb_initialized;
+#endif
+
+static char ppbuf[1024];
+
+void
+prom_printf(char *fmt, ...)
+{
+	va_list args;
+	char ch, *bptr;
+	int i;
+
+	va_start(args, fmt);
+
+#ifdef CONFIG_KGDB
+	ppbuf[0] = 'O';
+	i = vsprintf(ppbuf + 1, fmt, args) + 1;
+#else
+	i = vsprintf(ppbuf, fmt, args);
+#endif
+
+	bptr = ppbuf;
+
+#if CONFIG_AP1000
+        ap_write(1,bptr,strlen(bptr));
+#else
+
+#ifdef CONFIG_KGDB
+	if (kgdb_initialized) {
+		printk("kgdb_initialized = %d\n", kgdb_initialized);
+		putpacket(bptr, 1);
+	} else
+#else
+	while((ch = *(bptr++)) != 0) {
+		if(ch == '\n')
+			prom_putchar('\r');
+
+		prom_putchar(ch);
+	}
+#endif
+#endif
+	va_end(args);
+	return;
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/sbus.c linux/arch/m68k/sun3/sbus.c
--- v2.3.16/linux/arch/m68k/sun3/sbus.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/sbus.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,25 @@
+/*
+ * SBus helper functions
+ *
+ * Sun3 don't have a sbus, but many of the used devices are also
+ * used on Sparc machines with sbus. To avoid having a lot of
+ * duplicate code, we provide necessary glue stuff to make using
+ * of the sbus driver code possible.
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+
+__initfunc(void sbus_init(void))
+{
+
+}
+
+void *sparc_alloc_io (u32 address, void *virtual, int len, char *name,
+                      u32 bus_type, int rdonly)
+{
+	return (void *)address;
+}
+
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/sun3/sun3ints.c linux/arch/m68k/sun3/sun3ints.c
--- v2.3.16/linux/arch/m68k/sun3/sun3ints.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/sun3/sun3ints.c	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,132 @@
+ /*
+ * linux/arch/m68k/sun3/sun3ints.c -- Sun-3 Linux interrupt handling code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/segment.h>
+#include <asm/intersil.h>
+#include <asm/oplib.h>
+#include <asm/sun3ints.h>
+
+extern void sun3_leds (unsigned char);
+
+void sun3_disable_interrupts(void)
+{
+	sun3_disable_irq(0);
+}
+
+void sun3_enable_interrupts(void)
+{
+	sun3_enable_irq(0);
+}	
+
+int led_pattern[8] = {
+       ~(0x80), ~(0x01),
+       ~(0x40), ~(0x02),
+       ~(0x20), ~(0x04),
+       ~(0x10), ~(0x08)
+};
+
+unsigned char* sun3_intreg;
+
+void sun3_init_IRQ(void)
+{
+}
+                                
+void sun3_insert_irq(irq_node_t **list, irq_node_t *node)
+{
+}
+
+void sun3_delete_irq(irq_node_t **list, void *dev_id)
+{
+}
+
+void sun3_free_irq(unsigned int irq, void *dev_id)
+{
+}
+
+void sun3_enable_irq(unsigned int irq)
+{
+	*sun3_intreg |=  (1<<irq);
+}
+
+void sun3_disable_irq(unsigned int irq)
+{
+	*sun3_intreg &= ~(1<<irq);
+}
+
+inline void sun3_do_irq(int irq, struct pt_regs *fp)
+{
+	kstat.irqs[0][SYS_IRQS + irq]++;
+	*sun3_intreg &= ~(1<<irq);
+	*sun3_intreg |=  (1<<irq);
+}
+
+int sun3_get_irq_list(char *buf)
+{
+	return 0;
+}
+
+static void sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
+{
+        kstat.irqs[0][SYS_IRQS + irq]++;
+        *sun3_intreg &= ~(1<<irq);
+	intersil_clear();
+        *sun3_intreg |=  (1<<irq);
+        do_timer(fp);
+        if(!(kstat.irqs[0][SYS_IRQS + irq] % 20))
+                sun3_leds(led_pattern[(kstat.irqs[0][SYS_IRQS+irq]%160)
+                /20]);
+}
+
+static void sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
+{
+	sun3_do_irq(irq,fp);
+	if(!(kstat.irqs[0][SYS_IRQS + irq] % 2000)) 
+		sun3_leds(led_pattern[(kstat.irqs[0][SYS_IRQS+irq]%16000)/2000]);
+}
+
+/* handle requested ints, excepting 5 and 7, which always do the same
+   thing */
+static void *dev_ids[SYS_IRQS];
+static void (*inthandler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	NULL, NULL, NULL, NULL, NULL, sun3_int5, NULL, sun3_int7
+};
+
+static void sun3_inthandle(int irq, void *dev_id, struct pt_regs *fp)
+{
+	if(inthandler[irq] == NULL)
+		panic ("bad interrupt %d received (id %p)\n",irq, dev_id);
+
+        kstat.irqs[0][SYS_IRQS + irq]++;
+        *sun3_intreg &= ~(1<<irq);
+
+	inthandler[irq](irq, dev_ids[irq], fp);
+}
+
+void (*sun3_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = {
+	sun3_inthandle, sun3_inthandle, sun3_inthandle, sun3_inthandle,
+	sun3_inthandle, sun3_int5, sun3_inthandle, sun3_int7
+};
+
+int sun3_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+                      unsigned long flags, const char *devname, void *dev_id)
+{
+	if(inthandler[irq] != NULL)
+		return -1;
+
+	inthandler[irq] = handler;
+	dev_ids[irq] = dev_id;
+
+	return 0;
+}
+                        
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/vmlinux-sun3.lds linux/arch/m68k/vmlinux-sun3.lds
--- v2.3.16/linux/arch/m68k/vmlinux-sun3.lds	Wed Dec 31 16:00:00 1969
+++ linux/arch/m68k/vmlinux-sun3.lds	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,68 @@
+/* ld script to make m68k Linux kernel */
+OUTPUT_FORMAT("elf32-m68k", "elf32-m68k", "elf32-m68k")
+OUTPUT_ARCH(m68k)
+ENTRY(_start)
+SECTIONS
+{
+  . = 0xE004000;
+  _text = .;			/* Text and read-only data */
+  .text : {
+	*(.head)
+	*(.text)
+	*(.fixup)
+	*(.text.lock)		/* out-of-line lock text */
+	*(.gnu.warning)
+	} = 0x4e75
+  .kstrtab : { *(.kstrtab) }
+
+
+  _etext = .;			/* End of text section */
+
+  .data : {			/* Data */
+	*(.rodata)
+	*(.data)
+	CONSTRUCTORS
+  	. = ALIGN(16);		/* Exception table */
+  	__start___ex_table = .;
+  	*(__ex_table) 
+  	__stop___ex_table = .;
+  	__start___ksymtab = .;	/* Kernel symbol table */
+  	*(__ksymtab) 
+  	__stop___ksymtab = .;
+	}
+  /* End of data goes *here* so that freeing init code works properly. */
+  _edata = .;
+
+  . = ALIGN(8192);	/* Init code and data */
+__init_begin = .;
+  	.text.init : { *(.text.init) }
+  	.data.init : { *(.data.init) }
+	. = ALIGN(16);
+	__setup_start = .;
+	.setup.init : { *(.setup.init) }
+	__setup_end = .;
+	__initcall_start = .;
+	.initcall.init : { *(.initcall.init) }
+	__initcall_end = .;
+	. = ALIGN(8192);
+	__init_end = .;
+	.init.task : { *(init_task) }
+	
+
+  .bss : { *(.bss) }		/* BSS */
+
+  _end = . ;
+
+  .crap : {
+  	/* Stabs debugging sections.  */
+	*(.stab)
+	*(.stabstr)
+	*(.stab.excl)
+	*(.stab.exclstr)
+	*(.stab.index)
+	*(.stab.indexstr)
+	*(.comment)
+	*(.note)
+  }
+
+}
diff -u --recursive --new-file v2.3.16/linux/arch/m68k/vmlinux.lds linux/arch/m68k/vmlinux.lds
--- v2.3.16/linux/arch/m68k/vmlinux.lds	Mon Aug  9 12:27:30 1999
+++ linux/arch/m68k/vmlinux.lds	Sat Sep  4 13:06:41 1999
@@ -31,10 +31,12 @@
 	CONSTRUCTORS
 	}
 
-  _edata = .;			/* End of data section */
+  .bss : { *(.bss) }		/* BSS */
 
-  . = ALIGN(8192);
-  init_task : { *(init_task) }
+  . = ALIGN(16);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+  _edata = .;			/* End of data section */
 
   . = ALIGN(4096);		/* Init code and data */
   __init_begin = .;
@@ -50,13 +52,8 @@
   . = ALIGN(8192);
   __init_end = .;
 
-  . = ALIGN(16);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  init_task : { *(init_task) }	/* The initial task and kernel stack */
 
-  __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
   _end = . ;
 
   /* Stabs debugging sections.  */
diff -u --recursive --new-file v2.3.16/linux/arch/mips/kernel/head.S linux/arch/mips/kernel/head.S
--- v2.3.16/linux/arch/mips/kernel/head.S	Fri Jun 25 17:40:12 1999
+++ linux/arch/mips/kernel/head.S	Wed Sep  1 14:12:09 1999
@@ -16,7 +16,7 @@
  * Head.S contains the MIPS exception handler and startup code.
  */
 #include <linux/config.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 #include <asm/asm.h>
 #include <asm/cacheops.h>
diff -u --recursive --new-file v2.3.16/linux/arch/ppc/kernel/gemini_prom.S linux/arch/ppc/kernel/gemini_prom.S
--- v2.3.16/linux/arch/ppc/kernel/gemini_prom.S	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/gemini_prom.S	Wed Sep  1 15:34:01 1999
@@ -10,7 +10,6 @@
 
 #include "ppc_asm.tmpl"
 #include "ppc_defs.h"
-#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/gemini.h>
diff -u --recursive --new-file v2.3.16/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.3.16/linux/arch/ppc/kernel/gemini_setup.c	Tue Aug 31 17:29:12 1999
+++ linux/arch/ppc/kernel/gemini_setup.c	Wed Sep  1 15:34:01 1999
@@ -15,7 +15,6 @@
 #include <linux/errno.h> 
 #include <linux/reboot.h>
 #include <linux/pci.h>
-#include <linux/stddef.h>
 #include <linux/kdev_t.h>
 #include <linux/types.h>
 #include <linux/major.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/irq_onchip.c linux/arch/sh/kernel/irq_onchip.c
--- v2.3.16/linux/arch/sh/kernel/irq_onchip.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/irq_onchip.c	Wed Sep  1 15:34:01 1999
@@ -7,7 +7,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/process.c linux/arch/sh/kernel/process.c
--- v2.3.16/linux/arch/sh/kernel/process.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/process.c	Wed Sep  1 15:34:01 1999
@@ -26,7 +26,6 @@
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/interrupt.h>
-#include <linux/config.h>
 #include <linux/unistd.h>
 #include <linux/delay.h>
 #include <linux/reboot.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/ptrace.c linux/arch/sh/kernel/ptrace.c
--- v2.3.16/linux/arch/sh/kernel/ptrace.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/ptrace.c	Wed Sep  1 15:34:01 1999
@@ -3,7 +3,6 @@
  * linux/arch/sh/kernel/ptrace.c
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/time.c linux/arch/sh/kernel/time.c
--- v2.3.16/linux/arch/sh/kernel/time.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/time.c	Wed Sep  1 15:34:01 1999
@@ -26,7 +26,6 @@
 #include <asm/delay.h>
 
 #include <linux/timex.h>
-#include <linux/config.h>
 #include <linux/irq.h>
 
 #define TMU_TOCR	0xfffffe90	/* Byte access */
diff -u --recursive --new-file v2.3.16/linux/arch/sh/kernel/traps.c linux/arch/sh/kernel/traps.c
--- v2.3.16/linux/arch/sh/kernel/traps.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/kernel/traps.c	Wed Sep  1 15:34:01 1999
@@ -8,7 +8,6 @@
  * 'Traps.c' handles hardware traps and faults after we have saved some
  * state in 'entry.S'.
  */
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sh/mm/fault.c linux/arch/sh/mm/fault.c
--- v2.3.16/linux/arch/sh/mm/fault.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/mm/fault.c	Wed Sep  1 15:34:01 1999
@@ -23,7 +23,6 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/hardirq.h>
-#include <asm/uaccess.h>	/* to get __m() macro */
 #include <asm/mmu_context.h>
 
 extern void die(const char *,struct pt_regs *,long);
diff -u --recursive --new-file v2.3.16/linux/arch/sh/vmlinux.lds.S linux/arch/sh/vmlinux.lds.S
--- v2.3.16/linux/arch/sh/vmlinux.lds.S	Tue Aug 31 17:29:13 1999
+++ linux/arch/sh/vmlinux.lds.S	Wed Sep  1 15:34:01 1999
@@ -1,6 +1,7 @@
 /* ld script to make SuperH Linux kernel
  * Written by Niibe Yutaka
  */
+#include <linux/config.h>
 #ifdef CONFIG_LITTLE_ENDIAN
 OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl")
 #else
diff -u --recursive --new-file v2.3.16/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c
--- v2.3.16/linux/arch/sparc/ap1000/msc.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/ap1000/msc.c	Wed Sep  1 14:12:09 1999
@@ -17,7 +17,7 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 #include <asm/ap1000/pgtapmmu.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 
diff -u --recursive --new-file v2.3.16/linux/arch/sparc/ap1000/sync.c linux/arch/sparc/ap1000/sync.c
--- v2.3.16/linux/arch/sparc/ap1000/sync.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/sync.c	Wed Sep  1 14:12:09 1999
@@ -10,7 +10,7 @@
 #include <asm/ap1000/apreg.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern int cap_cid0;
 extern unsigned _ncel, _ncelx, _ncely, _cid;
diff -u --recursive --new-file v2.3.16/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.3.16/linux/arch/sparc/kernel/smp.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/smp.c	Wed Sep  1 14:12:09 1999
@@ -8,7 +8,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sparc/kernel/sun4d_smp.c linux/arch/sparc/kernel/sun4d_smp.c
--- v2.3.16/linux/arch/sparc/kernel/sun4d_smp.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/sun4d_smp.c	Wed Sep  1 14:12:09 1999
@@ -11,7 +11,7 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sparc/kernel/sun4m_smp.c linux/arch/sparc/kernel/sun4m_smp.c
--- v2.3.16/linux/arch/sparc/kernel/sun4m_smp.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc/kernel/sun4m_smp.c	Wed Sep  1 14:12:09 1999
@@ -7,7 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.3.16/linux/arch/sparc64/kernel/devices.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/devices.c	Wed Sep  1 14:12:09 1999
@@ -5,7 +5,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
 
diff -u --recursive --new-file v2.3.16/linux/arch/sparc64/kernel/pci.c linux/arch/sparc64/kernel/pci.c
--- v2.3.16/linux/arch/sparc64/kernel/pci.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/pci.c	Wed Sep  1 15:34:01 1999
@@ -6,6 +6,7 @@
  * Copyright (C) 1999 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/sched.h>
diff -u --recursive --new-file v2.3.16/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.3.16/linux/arch/sparc64/kernel/smp.c	Tue Aug 31 17:29:13 1999
+++ linux/arch/sparc64/kernel/smp.c	Wed Sep  1 14:12:09 1999
@@ -7,7 +7,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
diff -u --recursive --new-file v2.3.16/linux/drivers/Makefile linux/drivers/Makefile
--- v2.3.16/linux/drivers/Makefile	Thu Aug 26 13:05:34 1999
+++ linux/drivers/Makefile	Fri Sep  3 12:43:54 1999
@@ -22,6 +22,10 @@
 SUB_DIRS += pci
 endif
 
+ifdef CONFIG_PCMCIA
+SUB_DIRS += pcmcia
+endif
+
 ifdef CONFIG_SBUS
 SUB_DIRS += sbus
 MOD_SUB_DIRS += sbus
diff -u --recursive --new-file v2.3.16/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.3.16/linux/drivers/block/Config.in	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/Config.in	Tue Sep  7 11:23:40 1999
@@ -11,6 +11,11 @@
 if [ "$CONFIG_ATARI" = "y" ]; then
   tristate 'Atari floppy support' CONFIG_ATARI_FLOPPY
 fi
+if [ "$CONFIG_MAC" = "y" ]; then
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    bool 'Macintosh IIfx/Quadra 900/Quadra 950 floppy support (EXPERIMENTAL)' CONFIG_BLK_DEV_SWIM_IOP
+  fi
+fi
 
 tristate 'Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE
 comment 'Please see Documentation/ide.txt for help/info on IDE drives'
diff -u --recursive --new-file v2.3.16/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.3.16/linux/drivers/block/Makefile	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/Makefile	Tue Sep  7 11:23:40 1999
@@ -54,6 +54,10 @@
   endif
 endif
 
+ifeq ($(CONFIG_BLK_DEV_SWIM_IOP),y)
+  L_OBJS += swim_iop.o
+endif
+
 ifeq ($(CONFIG_ATARI_ACSI),y)
   LX_OBJS += acsi.o
 else
@@ -136,6 +140,10 @@
 
 ifeq ($(CONFIG_BLK_DEV_GAYLE),y)
 IDE_OBJS += gayle.o
+endif
+
+ifeq ($(CONFIG_BLK_DEV_Q40IDE),y)
+IDE_OBJS += q40ide.o
 endif
 
 ifeq ($(CONFIG_BLK_DEV_HD),y)
diff -u --recursive --new-file v2.3.16/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- v2.3.16/linux/drivers/block/amiflop.c	Tue Jul  6 19:05:48 1999
+++ linux/drivers/block/amiflop.c	Sat Sep  4 13:07:19 1999
@@ -135,10 +135,10 @@
 static struct fd_drive_type drive_types[] = {
 /*  code	name	   tr he   rdsz   wrsz sm pc1 pc2 sd  st st*/
 /*  warning: times are now in milliseconds (ms)                    */
- { FD_DD_3,	"DD 3.5",  80, 2, 14716, 13630, 1, 80,161, 3, 18, 1},
- { FD_HD_3,	"HD 3.5",  80, 2, 28344, 27258, 2, 80,161, 3, 18, 1},
- { FD_DD_5,	"DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},
- { FD_NODRIVE, "No Drive", 0, 0,     0,     0, 0,  0,  0,  0,  0, 0}
+{ FD_DD_3,	"DD 3.5",  80, 2, 14716, 13630, 1, 80,161, 3, 18, 1},
+{ FD_HD_3,	"HD 3.5",  80, 2, 28344, 27258, 2, 80,161, 3, 18, 1},
+{ FD_DD_5,	"DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},
+{ FD_NODRIVE, "No Drive", 0, 0,     0,     0, 0,  0,  0,  0,  0, 0}
 };
 static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
 
@@ -150,8 +150,8 @@
 static int amiga_read(int), dos_read(int);
 static void amiga_write(int), dos_write(int);
 static struct fd_data_type data_types[] = {
-  { "Amiga", 11 , amiga_read, amiga_write},
-  { "MS-Dos", 9, dos_read, dos_write}
+	{ "Amiga", 11 , amiga_read, amiga_write},
+	{ "MS-Dos", 9, dos_read, dos_write}
 };
 
 /* current info on each unit */
@@ -189,8 +189,8 @@
 
 /* MS-Dos MFM Coding tables (should go quick and easy) */
 static unsigned char mfmencode[16]={
-  0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
-  0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
+	0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,
+	0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55
 };
 static unsigned char mfmdecode[128];
 
@@ -231,29 +231,29 @@
 
 static void ms_isr(int irq, void *dummy, struct pt_regs *fp)
 {
-ms_busy = -1;
-wake_up(&ms_wait);
+	ms_busy = -1;
+	wake_up(&ms_wait);
 }
 
 /* all waits are queued up 
    A more generic routine would do a schedule a la timer.device */
 static void ms_delay(int ms)
 {
-  unsigned long flags;
-  int ticks;
-  if (ms > 0) {
-    save_flags(flags);
-    cli();
-    while (ms_busy == 0)
-      sleep_on(&ms_wait);
-    ms_busy = 0;
-    restore_flags(flags);
-    ticks = MS_TICKS*ms-1;
-    ciaa.tblo=ticks%256;
-    ciaa.tbhi=ticks/256;
-    ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */
-    sleep_on(&ms_wait);
-  }
+	unsigned long flags;
+	int ticks;
+	if (ms > 0) {
+		save_flags(flags);
+		cli();
+		while (ms_busy == 0)
+			sleep_on(&ms_wait);
+		ms_busy = 0;
+		restore_flags(flags);
+		ticks = MS_TICKS*ms-1;
+		ciaa.tblo=ticks%256;
+		ciaa.tbhi=ticks/256;
+		ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */
+		sleep_on(&ms_wait);
+	}
 }
 
 /* Hardware semaphore */
@@ -267,33 +267,33 @@
 
 static void get_fdc(int drive)
 {
-unsigned long flags;
+	unsigned long flags;
 
-       drive &= 3;
+	drive &= 3;
 #ifdef DEBUG
-       printk("get_fdc: drive %d  fdc_busy %d  fdc_nested %d\n",drive,fdc_busy,fdc_nested);
+	printk("get_fdc: drive %d  fdc_busy %d  fdc_nested %d\n",drive,fdc_busy,fdc_nested);
 #endif
-       save_flags(flags);
-       cli();
-       while (!try_fdc(drive))
-	       sleep_on(&fdc_wait);
-       fdc_busy = drive;
-       fdc_nested++;
-       restore_flags(flags);
+	save_flags(flags);
+	cli();
+	while (!try_fdc(drive))
+		sleep_on(&fdc_wait);
+	fdc_busy = drive;
+	fdc_nested++;
+	restore_flags(flags);
 }
 
 static inline void rel_fdc(void)
 {
 #ifdef DEBUG
-       if (fdc_nested == 0)
-         printk("fd: unmatched rel_fdc\n");
-       printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested);
-#endif
-       fdc_nested--;
-       if (fdc_nested == 0) {
-         fdc_busy = -1;
-         wake_up(&fdc_wait);
-       }
+	if (fdc_nested == 0)
+		printk("fd: unmatched rel_fdc\n");
+	printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested);
+#endif
+	fdc_nested--;
+	if (fdc_nested == 0) {
+		fdc_busy = -1;
+		wake_up(&fdc_wait);
+	}
 }
 
 static void fd_select (int drive)
@@ -395,9 +395,9 @@
 
 static void fd_motor_off(unsigned long drive)
 {
-long calledfromint;
+	long calledfromint;
 #ifdef MODULE
-long decusecount;
+	long decusecount;
 
 	decusecount = drive & 0x40000000;
 #endif
@@ -416,18 +416,18 @@
 
 #ifdef MODULE
 /*
-this is the last interrupt for any drive access, happens after
-release (from floppy_off). So we have to wait until now to decrease
-the use count.
+  this is the last interrupt for any drive access, happens after
+  release (from floppy_off). So we have to wait until now to decrease
+  the use count.
 */
-       if (decusecount)
-         MOD_DEC_USE_COUNT;
+	if (decusecount)
+		MOD_DEC_USE_COUNT;
 #endif
 }
 
 static void floppy_off (unsigned int nr)
 {
-int drive;
+	int drive;
 
 	drive = nr & 3;
 	del_timer(motor_off_timer + drive);
@@ -588,29 +588,29 @@
          * type.
          */
         if(drive == 0 && id == FD_NODRIVE)
-         {
+	{
                 id = fd_def_df0;
                 printk(KERN_NOTICE "fd: drive 0 didn't identify, setting default %08lx\n", (ulong)fd_def_df0);
-         }
+	}
 	/* return the ID value */
 	return (id);
 }
 
 static void fd_block_done(int irq, void *dummy, struct pt_regs *fp)
 {
-  if (block_flag)
-    custom.dsklen = 0x4000;
+	if (block_flag)
+		custom.dsklen = 0x4000;
 
-  if (block_flag == 2) { /* writing */
-    writepending = 2;
-    post_write_timer.expires = jiffies + 1; /* at least 2 ms */
-    post_write_timer.data = selected;
-    add_timer(&post_write_timer);
-  }
-  else {                /* reading */
-    block_flag = 0;
-    wake_up (&wait_fd_block);
-  }
+	if (block_flag == 2) { /* writing */
+		writepending = 2;
+		post_write_timer.expires = jiffies + 1; /* at least 2 ms */
+		post_write_timer.data = selected;
+		add_timer(&post_write_timer);
+	}
+	else {                /* reading */
+		block_flag = 0;
+		wake_up (&wait_fd_block);
+	}
 }
 
 static void raw_read(int drive)
@@ -680,17 +680,17 @@
 static void post_write (unsigned long drive)
 {
 #ifdef DEBUG
-  printk("post_write for drive %ld\n",drive);
+	printk("post_write for drive %ld\n",drive);
 #endif
-  drive &= 3;
-  custom.dsklen = 0;
-  block_flag = 0;
-  writepending = 0;
-  writefromint = 0;
-  unit[drive].dirty = 0;
-  wake_up(&wait_fd_block);
-  fd_deselect(drive);
-  rel_fdc(); /* corresponds to get_fdc() in raw_write */
+	drive &= 3;
+	custom.dsklen = 0;
+	block_flag = 0;
+	writepending = 0;
+	writefromint = 0;
+	unit[drive].dirty = 0;
+	wake_up(&wait_fd_block);
+	fd_deselect(drive);
+	rel_fdc(); /* corresponds to get_fdc() in raw_write */
 }
 
 
@@ -727,7 +727,7 @@
 }
 
 static unsigned long decode (unsigned long *data, unsigned long *raw,
-				   int len)
+			     int len)
 {
 	ulong *odd, *even;
 
@@ -822,34 +822,34 @@
 
 static void encode(unsigned long data, unsigned long *dest)
 {
-  unsigned long data2;
+	unsigned long data2;
 
-  data &= 0x55555555;
-  data2 = data ^ 0x55555555;
-  data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
+	data &= 0x55555555;
+	data2 = data ^ 0x55555555;
+	data |= ((data2 >> 1) | 0x80000000) & (data2 << 1);
 
-  if (*(dest - 1) & 0x00000001)
-    data &= 0x7FFFFFFF;
+	if (*(dest - 1) & 0x00000001)
+		data &= 0x7FFFFFFF;
 
-  *dest = data;
+	*dest = data;
 }
 
 static void encode_block(unsigned long *dest, unsigned long *src, int len)
 {
-  int cnt, to_cnt = 0;
-  unsigned long data;
+	int cnt, to_cnt = 0;
+	unsigned long data;
+
+	/* odd bits */
+	for (cnt = 0; cnt < len / 4; cnt++) {
+		data = src[cnt] >> 1;
+		encode(data, dest + to_cnt++);
+	}
 
-  /* odd bits */
-  for (cnt = 0; cnt < len / 4; cnt++) {
-    data = src[cnt] >> 1;
-    encode(data, dest + to_cnt++);
-  }
-
-  /* even bits */
-  for (cnt = 0; cnt < len / 4; cnt++) {
-    data = src[cnt];
-    encode(data, dest + to_cnt++);
-  }
+	/* even bits */
+	for (cnt = 0; cnt < len / 4; cnt++) {
+		data = src[cnt];
+		encode(data, dest + to_cnt++);
+	}
 }
 
 static unsigned long *putsec(int disk, unsigned long *raw, int cnt)
@@ -904,15 +904,15 @@
 
 
 struct dos_header {
-unsigned char track,   /* 0-80 */
-              side,    /* 0-1 */
-              sec,     /* 0-...*/
-              len_desc;/* 2 */
-unsigned short crc;     /* on 68000 we got an alignment problem, 
-                           but this compiler solves it  by adding silently 
-                           adding a pad byte so data won't fit
-                           and this took about 3h to discover.... */
-unsigned char gap1[22];     /* for longword-alignedness (0x4e) */
+	unsigned char track,   /* 0-80 */
+		side,    /* 0-1 */
+		sec,     /* 0-...*/
+		len_desc;/* 2 */
+	unsigned short crc;     /* on 68000 we got an alignment problem, 
+				   but this compiler solves it  by adding silently 
+				   adding a pad byte so data won't fit
+				   and this took about 3h to discover.... */
+	unsigned char gap1[22];     /* for longword-alignedness (0x4e) */
 };
 
 /* crc routines are borrowed from the messydos-handler  */
@@ -972,299 +972,308 @@
 
 static ushort dos_crc(void * data_a3, int data_d0, int data_d1, int data_d3)
 {
-static unsigned char CRCTable1[] = {
-	0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
-	0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3,
-	0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5,
-	0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7,
-	0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9,
-	0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab,
-	0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d,
-	0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f,
-	0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60,
-	0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72,
-	0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44,
-	0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56,
-	0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28,
-	0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a,
-	0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c,
-	0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e
-};
-
-static unsigned char CRCTable2[] = {
-	0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,
-	0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde,
-	0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d,
-	0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc,
-	0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b,
-	0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a,
-	0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49,
-	0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78,
-	0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67,
-	0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56,
-	0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05,
-	0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34,
-	0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3,
-	0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92,
-	0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1,
-	0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0
-};
+	static unsigned char CRCTable1[] = {
+		0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,
+		0x12,0x02,0x32,0x22,0x52,0x42,0x72,0x62,0x93,0x83,0xb3,0xa3,0xd3,0xc3,0xf3,0xe3,
+		0x24,0x34,0x04,0x14,0x64,0x74,0x44,0x54,0xa5,0xb5,0x85,0x95,0xe5,0xf5,0xc5,0xd5,
+		0x36,0x26,0x16,0x06,0x76,0x66,0x56,0x46,0xb7,0xa7,0x97,0x87,0xf7,0xe7,0xd7,0xc7,
+		0x48,0x58,0x68,0x78,0x08,0x18,0x28,0x38,0xc9,0xd9,0xe9,0xf9,0x89,0x99,0xa9,0xb9,
+		0x5a,0x4a,0x7a,0x6a,0x1a,0x0a,0x3a,0x2a,0xdb,0xcb,0xfb,0xeb,0x9b,0x8b,0xbb,0xab,
+		0x6c,0x7c,0x4c,0x5c,0x2c,0x3c,0x0c,0x1c,0xed,0xfd,0xcd,0xdd,0xad,0xbd,0x8d,0x9d,
+		0x7e,0x6e,0x5e,0x4e,0x3e,0x2e,0x1e,0x0e,0xff,0xef,0xdf,0xcf,0xbf,0xaf,0x9f,0x8f,
+		0x91,0x81,0xb1,0xa1,0xd1,0xc1,0xf1,0xe1,0x10,0x00,0x30,0x20,0x50,0x40,0x70,0x60,
+		0x83,0x93,0xa3,0xb3,0xc3,0xd3,0xe3,0xf3,0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72,
+		0xb5,0xa5,0x95,0x85,0xf5,0xe5,0xd5,0xc5,0x34,0x24,0x14,0x04,0x74,0x64,0x54,0x44,
+		0xa7,0xb7,0x87,0x97,0xe7,0xf7,0xc7,0xd7,0x26,0x36,0x06,0x16,0x66,0x76,0x46,0x56,
+		0xd9,0xc9,0xf9,0xe9,0x99,0x89,0xb9,0xa9,0x58,0x48,0x78,0x68,0x18,0x08,0x38,0x28,
+		0xcb,0xdb,0xeb,0xfb,0x8b,0x9b,0xab,0xbb,0x4a,0x5a,0x6a,0x7a,0x0a,0x1a,0x2a,0x3a,
+		0xfd,0xed,0xdd,0xcd,0xbd,0xad,0x9d,0x8d,0x7c,0x6c,0x5c,0x4c,0x3c,0x2c,0x1c,0x0c,
+		0xef,0xff,0xcf,0xdf,0xaf,0xbf,0x8f,0x9f,0x6e,0x7e,0x4e,0x5e,0x2e,0x3e,0x0e,0x1e
+	};
+
+	static unsigned char CRCTable2[] = {
+		0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,
+		0x31,0x10,0x73,0x52,0xb5,0x94,0xf7,0xd6,0x39,0x18,0x7b,0x5a,0xbd,0x9c,0xff,0xde,
+		0x62,0x43,0x20,0x01,0xe6,0xc7,0xa4,0x85,0x6a,0x4b,0x28,0x09,0xee,0xcf,0xac,0x8d,
+		0x53,0x72,0x11,0x30,0xd7,0xf6,0x95,0xb4,0x5b,0x7a,0x19,0x38,0xdf,0xfe,0x9d,0xbc,
+		0xc4,0xe5,0x86,0xa7,0x40,0x61,0x02,0x23,0xcc,0xed,0x8e,0xaf,0x48,0x69,0x0a,0x2b,
+		0xf5,0xd4,0xb7,0x96,0x71,0x50,0x33,0x12,0xfd,0xdc,0xbf,0x9e,0x79,0x58,0x3b,0x1a,
+		0xa6,0x87,0xe4,0xc5,0x22,0x03,0x60,0x41,0xae,0x8f,0xec,0xcd,0x2a,0x0b,0x68,0x49,
+		0x97,0xb6,0xd5,0xf4,0x13,0x32,0x51,0x70,0x9f,0xbe,0xdd,0xfc,0x1b,0x3a,0x59,0x78,
+		0x88,0xa9,0xca,0xeb,0x0c,0x2d,0x4e,0x6f,0x80,0xa1,0xc2,0xe3,0x04,0x25,0x46,0x67,
+		0xb9,0x98,0xfb,0xda,0x3d,0x1c,0x7f,0x5e,0xb1,0x90,0xf3,0xd2,0x35,0x14,0x77,0x56,
+		0xea,0xcb,0xa8,0x89,0x6e,0x4f,0x2c,0x0d,0xe2,0xc3,0xa0,0x81,0x66,0x47,0x24,0x05,
+		0xdb,0xfa,0x99,0xb8,0x5f,0x7e,0x1d,0x3c,0xd3,0xf2,0x91,0xb0,0x57,0x76,0x15,0x34,
+		0x4c,0x6d,0x0e,0x2f,0xc8,0xe9,0x8a,0xab,0x44,0x65,0x06,0x27,0xc0,0xe1,0x82,0xa3,
+		0x7d,0x5c,0x3f,0x1e,0xf9,0xd8,0xbb,0x9a,0x75,0x54,0x37,0x16,0xf1,0xd0,0xb3,0x92,
+		0x2e,0x0f,0x6c,0x4d,0xaa,0x8b,0xe8,0xc9,0x26,0x07,0x64,0x45,0xa2,0x83,0xe0,0xc1,
+		0x1f,0x3e,0x5d,0x7c,0x9b,0xba,0xd9,0xf8,0x17,0x36,0x55,0x74,0x93,0xb2,0xd1,0xf0
+	};
 
 /* look at the asm-code - what looks in C a bit strange is almost as good as handmade */
-register int i;
-register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl;
+	register int i;
+	register unsigned char *CRCT1, *CRCT2, *data, c, crch, crcl;
 
-CRCT1=CRCTable1;
-CRCT2=CRCTable2;
-data=data_a3;
-crcl=data_d1;
-crch=data_d0;
-for (i=data_d3; i>=0; i--) {
-  c = (*data++) ^ crch;
-  crch = CRCT1[c] ^ crcl;
-  crcl = CRCT2[c];
-}
-return (crch<<8)|crcl;
+	CRCT1=CRCTable1;
+	CRCT2=CRCTable2;
+	data=data_a3;
+	crcl=data_d1;
+	crch=data_d0;
+	for (i=data_d3; i>=0; i--) {
+		c = (*data++) ^ crch;
+		crch = CRCT1[c] ^ crcl;
+		crcl = CRCT2[c];
+	}
+	return (crch<<8)|crcl;
 }
 
 static inline ushort dos_hdr_crc (struct dos_header *hdr)
 {
-return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */
+	return dos_crc(&(hdr->track), 0xb2, 0x30, 3); /* precomputed magic */
 }
 
 static inline ushort dos_data_crc(unsigned char *data)
 {
-return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
+	return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */
 }
 
 static inline unsigned char dos_decode_byte(ushort word)
 {
-register ushort w2;
-register unsigned char byte;
-register unsigned char *dec = mfmdecode;
-
-w2=word;
-w2>>=8;
-w2&=127;
-byte = dec[w2];
-byte <<= 4;
-w2 = word & 127;
-byte |= dec[w2];
-return byte;
+	register ushort w2;
+	register unsigned char byte;
+	register unsigned char *dec = mfmdecode;
+
+	w2=word;
+	w2>>=8;
+	w2&=127;
+	byte = dec[w2];
+	byte <<= 4;
+	w2 = word & 127;
+	byte |= dec[w2];
+	return byte;
 }
 
 static unsigned long dos_decode(unsigned char *data, unsigned short *raw, int len)
 {
-int i;
+	int i;
 
-for (i = 0; i < len; i++)
-  *data++=dos_decode_byte(*raw++);
-return ((ulong)raw);
+	for (i = 0; i < len; i++)
+		*data++=dos_decode_byte(*raw++);
+	return ((ulong)raw);
 }
 
 #ifdef DEBUG
 static void dbg(unsigned long ptr)
 {
-  printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n",ptr,
-    ((ulong *)ptr)[0],((ulong *)ptr)[1],((ulong *)ptr)[2],((ulong *)ptr)[3]);
+	printk("raw data @%08lx: %08lx, %08lx ,%08lx, %08lx\n", ptr,
+	       ((ulong *)ptr)[0], ((ulong *)ptr)[1],
+	       ((ulong *)ptr)[2], ((ulong *)ptr)[3]);
 }
 #endif
 
 static int dos_read(int drive)
 {
-  unsigned long end;
-  unsigned long raw;
-  int scnt;
-  unsigned short crc,data_crc[2];
-  struct dos_header hdr;
-
-  drive&=3;
-  raw = (long) raw_buf;
-  end = raw + unit[drive].type->read_size;
-
-  for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
-  do { /* search for the right sync of each sec-hdr */
-    if (!(raw = scan_sync (raw, end))) {
-      printk(KERN_INFO "dos_read: no hdr sync on track %d, unit %d for sector %d\n",
-        unit[drive].track,drive,scnt);
-      return MFM_NOSYNC;
-    }
+	unsigned long end;
+	unsigned long raw;
+	int scnt;
+	unsigned short crc,data_crc[2];
+	struct dos_header hdr;
+
+	drive&=3;
+	raw = (long) raw_buf;
+	end = raw + unit[drive].type->read_size;
+
+	for (scnt=0; scnt < unit[drive].dtype->sects * unit[drive].type->sect_mult; scnt++) {
+		do { /* search for the right sync of each sec-hdr */
+			if (!(raw = scan_sync (raw, end))) {
+				printk(KERN_INFO "dos_read: no hdr sync on "
+				       "track %d, unit %d for sector %d\n",
+				       unit[drive].track,drive,scnt);
+				return MFM_NOSYNC;
+			}
 #ifdef DEBUG
-  dbg(raw);
+			dbg(raw);
 #endif
-  } while (*((ushort *)raw)!=0x5554); /* loop usually only once done */
-  raw+=2; /* skip over headermark */
-  raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8);
-  crc = dos_hdr_crc(&hdr);
+		} while (*((ushort *)raw)!=0x5554); /* loop usually only once done */
+		raw+=2; /* skip over headermark */
+		raw = dos_decode((unsigned char *)&hdr,(ushort *) raw,8);
+		crc = dos_hdr_crc(&hdr);
 
 #ifdef DEBUG
-  printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side,
-     hdr.sec, hdr.len_desc, hdr.crc);
+		printk("(%3d,%d,%2d,%d) %x\n", hdr.track, hdr.side,
+		       hdr.sec, hdr.len_desc, hdr.crc);
 #endif
 
-  if (crc != hdr.crc) {
-    printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n", hdr.crc, crc);
-    return MFM_HEADER;
-  }
-  if (hdr.track != unit[drive].track/unit[drive].type->heads) {
-    printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n", hdr.track,
-      unit[drive].track/unit[drive].type->heads);
-    return MFM_TRACK;
-  }
-
-  if (hdr.side != unit[drive].track%unit[drive].type->heads) {
-    printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n", hdr.side,
-      unit[drive].track%unit[drive].type->heads);
-    return MFM_TRACK;
-  }
-
-  if (hdr.len_desc != 2) {
-    printk(KERN_INFO "dos_read: unknown sector len descriptor %d\n", hdr.len_desc);
-    return MFM_DATA;
-  }
+		if (crc != hdr.crc) {
+			printk(KERN_INFO "dos_read: MFM_HEADER %04x,%04x\n",
+			       hdr.crc, crc);
+			return MFM_HEADER;
+		}
+		if (hdr.track != unit[drive].track/unit[drive].type->heads) {
+			printk(KERN_INFO "dos_read: MFM_TRACK %d, %d\n",
+			       hdr.track,
+			       unit[drive].track/unit[drive].type->heads);
+			return MFM_TRACK;
+		}
+
+		if (hdr.side != unit[drive].track%unit[drive].type->heads) {
+			printk(KERN_INFO "dos_read: MFM_SIDE %d, %d\n",
+			       hdr.side,
+			       unit[drive].track%unit[drive].type->heads);
+			return MFM_TRACK;
+		}
+
+		if (hdr.len_desc != 2) {
+			printk(KERN_INFO "dos_read: unknown sector len "
+			       "descriptor %d\n", hdr.len_desc);
+			return MFM_DATA;
+		}
 #ifdef DEBUG
-  printk("hdr accepted\n");
+		printk("hdr accepted\n");
 #endif
-  if (!(raw = scan_sync (raw, end))) {
-    printk(KERN_INFO "dos_read: no data sync on track %d, unit %d for sector%d, disk sector %d\n",
-      unit[drive].track, drive, scnt, hdr.sec);
-    return MFM_NOSYNC;
-  }
+		if (!(raw = scan_sync (raw, end))) {
+			printk(KERN_INFO "dos_read: no data sync on track "
+			       "%d, unit %d for sector%d, disk sector %d\n",
+			       unit[drive].track, drive, scnt, hdr.sec);
+			return MFM_NOSYNC;
+		}
 #ifdef DEBUG
-  dbg(raw);
+		dbg(raw);
 #endif
 
-  if (*((ushort *)raw)!=0x5545) {
-    printk(KERN_INFO "dos_read: no data mark after sync (%d,%d,%d,%d) sc=%d\n",
-      hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt);
-    return MFM_NOSYNC;
-  }
-
-  raw+=2;  /* skip data mark (included in checksum) */
-  raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512);
-  raw = dos_decode((unsigned char  *)data_crc,(ushort *) raw,4);
-  crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512);
-
-  if (crc != data_crc[0]) {
-    printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) sc=%d, %x %x\n",
-      hdr.track, hdr.side, hdr.sec, hdr.len_desc,
-      scnt,data_crc[0], crc);
-    printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n",
-      ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0],
-      ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1],
-      ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2],
-      ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]);
-    return MFM_DATA;
-  }
-  }
- return 0;
+		if (*((ushort *)raw)!=0x5545) {
+			printk(KERN_INFO "dos_read: no data mark after "
+			       "sync (%d,%d,%d,%d) sc=%d\n",
+			       hdr.track,hdr.side,hdr.sec,hdr.len_desc,scnt);
+			return MFM_NOSYNC;
+		}
+
+		raw+=2;  /* skip data mark (included in checksum) */
+		raw = dos_decode((unsigned char *)(unit[drive].trackbuf + (hdr.sec - 1) * 512), (ushort *) raw, 512);
+		raw = dos_decode((unsigned char  *)data_crc,(ushort *) raw,4);
+		crc = dos_data_crc(unit[drive].trackbuf + (hdr.sec - 1) * 512);
+
+		if (crc != data_crc[0]) {
+			printk(KERN_INFO "dos_read: MFM_DATA (%d,%d,%d,%d) "
+			       "sc=%d, %x %x\n", hdr.track, hdr.side,
+			       hdr.sec, hdr.len_desc, scnt,data_crc[0], crc);
+			printk(KERN_INFO "data=(%lx,%lx,%lx,%lx,...)\n",
+			       ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[0],
+			       ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[1],
+			       ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[2],
+			       ((ulong *)(unit[drive].trackbuf+(hdr.sec-1)*512))[3]);
+			return MFM_DATA;
+		}
+	}
+	return 0;
 }
 
 static inline ushort dos_encode_byte(unsigned char byte)
 {
-register unsigned char *enc, b2, b1;
-register ushort word;
+	register unsigned char *enc, b2, b1;
+	register ushort word;
 
-enc=mfmencode;
-b1=byte;
-b2=b1>>4;
-b1&=15;
-word=enc[b2] <<8 | enc [b1];
-return (word|((word&(256|64)) ? 0: 128));
+	enc=mfmencode;
+	b1=byte;
+	b2=b1>>4;
+	b1&=15;
+	word=enc[b2] <<8 | enc [b1];
+	return (word|((word&(256|64)) ? 0: 128));
 }
 
 static void dos_encode_block(ushort *dest, unsigned char *src, int len)
 {
-int i;
+	int i;
 
-for (i = 0; i < len; i++) {
-  *dest=dos_encode_byte(*src++);
-  *dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000;
-  dest++;
-}
+	for (i = 0; i < len; i++) {
+		*dest=dos_encode_byte(*src++);
+		*dest|=((dest[-1]&1)||(*dest&0x4000))? 0: 0x8000;
+		dest++;
+	}
 }
 
 static unsigned long *ms_putsec(int drive, unsigned long *raw, int cnt)
 {
-static struct dos_header hdr={0,0,0,2,0,
-  {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}};
-int i;
-static ushort crc[2]={0,0x4e4e};
+	static struct dos_header hdr={0,0,0,2,0,
+	  {78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78}};
+	int i;
+	static ushort crc[2]={0,0x4e4e};
 
-drive&=3;
+	drive&=3;
 /* id gap 1 */
 /* the MFM word before is always 9254 */
-for(i=0;i<6;i++)
-  *raw++=0xaaaaaaaa;
+	for(i=0;i<6;i++)
+		*raw++=0xaaaaaaaa;
 /* 3 sync + 1 headermark */
-*raw++=0x44894489;
-*raw++=0x44895554;
+	*raw++=0x44894489;
+	*raw++=0x44895554;
 
 /* fill in the variable parts of the header */
-hdr.track=unit[drive].track/unit[drive].type->heads;
-hdr.side=unit[drive].track%unit[drive].type->heads;
-hdr.sec=cnt+1;
-hdr.crc=dos_hdr_crc(&hdr);
+	hdr.track=unit[drive].track/unit[drive].type->heads;
+	hdr.side=unit[drive].track%unit[drive].type->heads;
+	hdr.sec=cnt+1;
+	hdr.crc=dos_hdr_crc(&hdr);
 
 /* header (without "magic") and id gap 2*/
-dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28);
-raw+=14;
+	dos_encode_block((ushort *)raw,(unsigned char *) &hdr.track,28);
+	raw+=14;
 
 /*id gap 3 */
-for(i=0;i<6;i++)
-  *raw++=0xaaaaaaaa;
+	for(i=0;i<6;i++)
+		*raw++=0xaaaaaaaa;
 
 /* 3 syncs and 1 datamark */
-*raw++=0x44894489;
-*raw++=0x44895545;
+	*raw++=0x44894489;
+	*raw++=0x44895545;
 
 /* data */
-dos_encode_block((ushort *)raw,(unsigned char *)unit[drive].trackbuf+cnt*512,512);
-raw+=256;
+	dos_encode_block((ushort *)raw,
+			 (unsigned char *)unit[drive].trackbuf+cnt*512,512);
+	raw+=256;
 
 /*data crc + jd's special gap (long words :-/) */
-crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512);
-dos_encode_block((ushort *) raw,(unsigned char *)crc,4);
-raw+=2;
+	crc[0]=dos_data_crc(unit[drive].trackbuf+cnt*512);
+	dos_encode_block((ushort *) raw,(unsigned char *)crc,4);
+	raw+=2;
 
 /* data gap */
-for(i=0;i<38;i++)
-  *raw++=0x92549254;
+	for(i=0;i<38;i++)
+		*raw++=0x92549254;
 
-return raw; /* wrote 652 MFM words */
+	return raw; /* wrote 652 MFM words */
 }
 
 static void dos_write(int disk)
 {
-int cnt;
-unsigned long raw = (unsigned long) raw_buf;
-unsigned long *ptr=(unsigned long *)raw;
+	int cnt;
+	unsigned long raw = (unsigned long) raw_buf;
+	unsigned long *ptr=(unsigned long *)raw;
 
-disk&=3;
+	disk&=3;
 /* really gap4 + indexgap , but we write it first and round it up */
-for (cnt=0;cnt<425;cnt++)
-  *ptr++=0x92549254;
+	for (cnt=0;cnt<425;cnt++)
+		*ptr++=0x92549254;
 
 /* the following is just guessed */
-if (unit[disk].type->sect_mult==2)  /* check for HD-Disks */
-  for(cnt=0;cnt<473;cnt++)
-    *ptr++=0x92549254;
+	if (unit[disk].type->sect_mult==2)  /* check for HD-Disks */
+		for(cnt=0;cnt<473;cnt++)
+			*ptr++=0x92549254;
 
 /* now the index marks...*/
-for (cnt=0;cnt<20;cnt++)
-  *ptr++=0x92549254;
-for (cnt=0;cnt<6;cnt++)
-  *ptr++=0xaaaaaaaa;
-*ptr++=0x52245224;
-*ptr++=0x52245552;
-for (cnt=0;cnt<20;cnt++)
-  *ptr++=0x92549254;
+	for (cnt=0;cnt<20;cnt++)
+		*ptr++=0x92549254;
+	for (cnt=0;cnt<6;cnt++)
+		*ptr++=0xaaaaaaaa;
+	*ptr++=0x52245224;
+	*ptr++=0x52245552;
+	for (cnt=0;cnt<20;cnt++)
+		*ptr++=0x92549254;
 
 /* sectors */
-for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
-  ptr=ms_putsec(disk,ptr,cnt);
+	for(cnt = 0; cnt < unit[disk].dtype->sects * unit[disk].type->sect_mult; cnt++)
+		ptr=ms_putsec(disk,ptr,cnt);
 
-*(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */
+	*(ushort *)ptr = 0xaaa8; /* MFM word before is always 0x9254 */
 }
 
 /*
@@ -1299,37 +1308,38 @@
 
 static int non_int_flush_track (unsigned long nr)
 {
-unsigned long flags;
+	unsigned long flags;
 
-  nr&=3;
-  writefromint = 0;
-  del_timer(&post_write_timer);
-  get_fdc(nr);
-  if (!fd_motor_on(nr)) {
-  	writepending = 0;
-  	rel_fdc();
-  	return 0;
-  }
-  save_flags(flags);
-  cli();
-  if (writepending != 2) {
-    restore_flags(flags);
-    (*unit[nr].dtype->write_fkt)(nr);
-    if (!raw_write(nr)) {
-      printk (KERN_NOTICE "floppy disk write protected in write!\n");
-      writepending = 0;
-      return 0;
-    }
-    while (block_flag == 2)
-      sleep_on (&wait_fd_block);
-  }
-  else {
-    restore_flags(flags);
-    ms_delay(2); /* 2 ms post_write delay */
-    post_write(nr);
-  }
-  rel_fdc();
-  return 1;
+	nr&=3;
+	writefromint = 0;
+	del_timer(&post_write_timer);
+	get_fdc(nr);
+	if (!fd_motor_on(nr)) {
+		writepending = 0;
+		rel_fdc();
+		return 0;
+	}
+	save_flags(flags);
+	cli();
+	if (writepending != 2) {
+		restore_flags(flags);
+		(*unit[nr].dtype->write_fkt)(nr);
+		if (!raw_write(nr)) {
+			printk (KERN_NOTICE "floppy disk write protected "
+				"in write!\n");
+			writepending = 0;
+			return 0;
+		}
+		while (block_flag == 2)
+			sleep_on (&wait_fd_block);
+	}
+	else {
+		restore_flags(flags);
+		ms_delay(2); /* 2 ms post_write delay */
+		post_write(nr);
+	}
+	rel_fdc();
+	return 1;
 }
 
 static int get_track(int drive, int track)
@@ -1379,7 +1389,7 @@
 		return;
 	}
 
-    repeat:
+ repeat:
 	if (!CURRENT) {
 		/* Nothing left to do */
 		return;
@@ -1406,11 +1416,12 @@
 		floppy = unit + drive;
 	}
 
- /* Here someone could investigate to be more efficient */
+	/* Here someone could investigate to be more efficient */
 	for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) { 
 #ifdef DEBUG
-		printk("fd: sector %ld + %d requested for %s\n",CURRENT->sector,cnt,
-			(CURRENT->cmd==READ)?"read":"write");
+		printk("fd: sector %ld + %d requested for %s\n",
+		       CURRENT->sector,cnt,
+		       (CURRENT->cmd==READ)?"read":"write");
 #endif
 		block = CURRENT->sector + cnt;
 		if ((int)block > floppy->blocks) {
@@ -1422,8 +1433,8 @@
 		sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
 		data = CURRENT->buffer + 512 * cnt;
 #ifdef DEBUG
-		printk("access to track %d, sector %d, with buffer at 0x%08lx\n",
-			track, sector, data);
+		printk("access to track %d, sector %d, with buffer at "
+		       "0x%08lx\n", track, sector, data);
 #endif
 
 		if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
@@ -1437,11 +1448,11 @@
 		}
 
 		switch (CURRENT->cmd) {
-		    case READ:
+		case READ:
 			memcpy(data, unit[drive].trackbuf + sector * 512, 512);
 			break;
 
-		    case WRITE:
+		case WRITE:
 			memcpy(unit[drive].trackbuf + sector * 512, data, 512);
 
 			/* keep the drive spinning while writes are scheduled */
@@ -1494,7 +1505,7 @@
 		loc.cylinders = unit[drive].type->tracks;
 		loc.start = 0;
 		if (copy_to_user((void *)param, (void *)&loc,
-					  sizeof(struct hd_geometry)))
+				 sizeof(struct hd_geometry)))
 			return -EFAULT;
 		break;
 	}
@@ -1545,10 +1556,10 @@
 		getprm.sect=unit[drive].dtype->sects * unit[drive].type->sect_mult;
 		getprm.size=unit[drive].blocks;
 		if (copy_to_user((void *)param,
-					  (void *)&getprm,
-					  sizeof(struct floppy_struct)))
+				 (void *)&getprm,
+				 sizeof(struct floppy_struct)))
 			return -EFAULT;
-	    break;
+		break;
 	case BLKGETSIZE:
 		return put_user(unit[drive].blocks,(long *)param);
 		break;
@@ -1562,13 +1573,14 @@
 #ifdef RAW_IOCTL
 	case IOCTL_RAW_TRACK:
 		if (copy_to_user((void *)param, raw_buf,
-				     unit[drive].type->read_size))
+				 unit[drive].type->read_size))
 			return -EFAULT;
 		else
 			return unit[drive].type->read_size;
 #endif
 	default:
-		printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",cmd,drive);
+		printk(KERN_DEBUG "fd_ioctl: unknown cmd %d for drive %d.",
+		       cmd, drive);
 		return -ENOSYS;
 	}
 	return 0;
@@ -1589,8 +1601,8 @@
 			break;
 
 	if (type >= num_dr_types) {
-		printk(KERN_WARNING "fd_probe: unsupported drive type %08lx found\n",
-		       code);
+		printk(KERN_WARNING "fd_probe: unsupported drive type "
+		       "%08lx found\n", code);
 		unit[drive].type = &drive_types[num_dr_types-1]; /* FD_NODRIVE */
 		return;
 	}
@@ -1611,93 +1623,93 @@
  */
 static int floppy_open(struct inode *inode, struct file *filp)
 {
-  int drive;
-  int old_dev;
-  int system;
-  unsigned long flags;
-
-  drive = MINOR(inode->i_rdev) & 3;
-  old_dev = fd_device[drive];
-
-  if (fd_ref[drive])
-    if (old_dev != inode->i_rdev)
-      return -EBUSY;
-
-  if (unit[drive].type->code == FD_NODRIVE)
-    return -ENODEV;
-
-  if (filp && filp->f_mode & 3) {
-    check_disk_change(inode->i_rdev);
-    if (filp->f_mode & 2 ) {
-	  int wrprot;
-
-	  get_fdc(drive);
-	  fd_select (drive);
-	  wrprot = !(ciaa.pra & DSKPROT);
-	  fd_deselect (drive);
-	  rel_fdc();
-
-	  if (wrprot)
-		  return -EROFS;
-    }
-  }
-
-  save_flags(flags);
-  cli();
-  fd_ref[drive]++;
-  fd_device[drive] = inode->i_rdev;
+	int drive;
+	int old_dev;
+	int system;
+	unsigned long flags;
+
+	drive = MINOR(inode->i_rdev) & 3;
+	old_dev = fd_device[drive];
+
+	if (fd_ref[drive])
+		if (old_dev != inode->i_rdev)
+			return -EBUSY;
+
+	if (unit[drive].type->code == FD_NODRIVE)
+		return -ENODEV;
+
+	if (filp && filp->f_mode & 3) {
+		check_disk_change(inode->i_rdev);
+		if (filp->f_mode & 2 ) {
+			int wrprot;
+
+			get_fdc(drive);
+			fd_select (drive);
+			wrprot = !(ciaa.pra & DSKPROT);
+			fd_deselect (drive);
+			rel_fdc();
+
+			if (wrprot)
+				return -EROFS;
+		}
+	}
+
+	save_flags(flags);
+	cli();
+	fd_ref[drive]++;
+	fd_device[drive] = inode->i_rdev;
 #ifdef MODULE
-  if (unit[drive].motor == 0)
-    MOD_INC_USE_COUNT;
+	if (unit[drive].motor == 0)
+		MOD_INC_USE_COUNT;
 #endif
-  restore_flags(flags);
+	restore_flags(flags);
 
-  if (old_dev && old_dev != inode->i_rdev)
-    invalidate_buffers(old_dev);
+	if (old_dev && old_dev != inode->i_rdev)
+		invalidate_buffers(old_dev);
 
-  system=(inode->i_rdev & 4)>>2;
-  unit[drive].dtype=&data_types[system];
-  unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
+	system=(inode->i_rdev & 4)>>2;
+	unit[drive].dtype=&data_types[system];
+	unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks*
 		data_types[system].sects*unit[drive].type->sect_mult;
-  floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1;
+	floppy_sizes[MINOR(inode->i_rdev)] = unit[drive].blocks >> 1;
 
-  printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
-	unit[drive].type->name, data_types[system].name);
+	printk(KERN_INFO "fd%d: accessing %s-disk with %s-layout\n",drive,
+	       unit[drive].type->name, data_types[system].name);
 
-  return 0;
+	return 0;
 }
 
 static int floppy_release(struct inode * inode, struct file * filp)
 {
 #ifdef DEBUG
-  struct super_block * sb;
+	struct super_block * sb;
 #endif
-  int drive = MINOR(inode->i_rdev) & 3;
+	int drive = MINOR(inode->i_rdev) & 3;
 
-  fsync_dev(inode->i_rdev);
+	fsync_dev(inode->i_rdev);
 
 #ifdef DEBUG
-  /* This is now handled in floppy_change, but still useful for debugging */
-  sb = get_super(inode->i_rdev);
-  if (sb)
-	  invalidate_inodes(sb);
-  invalidate_buffers(inode->i_rdev);
+	/* This is now handled in floppy_change, but still useful for debugging */
+	sb = get_super(inode->i_rdev);
+	if (sb)
+		invalidate_inodes(sb);
+	invalidate_buffers(inode->i_rdev);
 #endif
 
-  if (unit[drive].dirty == 1) {
-	  del_timer (flush_track_timer + drive);
-	  non_int_flush_track (drive);
-  }
+	if (unit[drive].dirty == 1) {
+		del_timer (flush_track_timer + drive);
+		non_int_flush_track (drive);
+	}
   
-  if (!fd_ref[drive]--) {
-    printk(KERN_CRIT "floppy_release with fd_ref == 0");
-    fd_ref[drive] = 0;
-  }
+	if (!fd_ref[drive]--) {
+		printk(KERN_CRIT "floppy_release with fd_ref == 0");
+		fd_ref[drive] = 0;
+	}
 #ifdef MODULE
 /* the mod_use counter is handled this way */
-  floppy_off (drive | 0x40000000);
+	floppy_off (drive | 0x40000000);
 #endif
-  return 0;
+	return 0;
 }
 
 /*
@@ -1769,23 +1781,23 @@
 	drives=0;
 	nomem=0;
 	for(drive=0;drive<FD_MAX_UNITS;drive++) {
-	  fd_probe(drive);
-	  if (unit[drive].type->code != FD_NODRIVE) {
-	    drives++;
-	    if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
-	      printk("no mem for ");
-	      unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */
-	      drives--;
-	      nomem = 1;
-	    }
-	    printk("fd%d ",drive);
-	  }
+		fd_probe(drive);
+		if (unit[drive].type->code != FD_NODRIVE) {
+			drives++;
+			if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) {
+				printk("no mem for ");
+				unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */
+				drives--;
+				nomem = 1;
+			}
+			printk("fd%d ",drive);
+		}
 	}
 	if ((drives > 0) || (nomem == 0)) {
-	  if (drives == 0)
-	    printk("no drives");
-	  printk("\n");
-	  return drives;
+		if (drives == 0)
+			printk("no drives");
+		printk("\n");
+		return drives;
 	}
 	printk("\n");
 	return -ENOMEM;
@@ -1793,85 +1805,87 @@
 
 int __init amiga_floppy_init(void)
 {
-  int i;
+	int i;
+
+	if (!AMIGAHW_PRESENT(AMI_FLOPPY))
+		return -ENXIO;
 
-  if (!AMIGAHW_PRESENT(AMI_FLOPPY))
-    return -ENXIO;
-  if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
-    printk("fd: Unable to get major %d for floppy\n",MAJOR_NR);
-    return -EBUSY;
-  }
-  if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) {
-  	printk("fd: cannot get chip mem buffer\n");
-  	unregister_blkdev(MAJOR_NR,"fd");
-  	return -ENOMEM;
-  }
-
-  if (request_irq(IRQ_FLOPPY, fd_block_done, 0, "floppy_dma", NULL) != 0) {
-  	printk("fd: cannot get irq for dma\n");
-  	amiga_chip_free(raw_buf);
-  	unregister_blkdev(MAJOR_NR,"fd");
-  	return -EBUSY;
-  }
-  if (request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL) != 0) {
-  	printk("fd: cannot get irq for timer\n");
-  	free_irq(IRQ_FLOPPY, NULL);
-  	amiga_chip_free(raw_buf);
-  	unregister_blkdev(MAJOR_NR,"fd");
-  	return -EBUSY;
-  }
-  if (fd_probe_drives() < 1) { /* No usable drives */
-  	free_irq(IRQ_AMIGA_CIAA_TB, NULL);
-  	free_irq(IRQ_FLOPPY, NULL);
-  	amiga_chip_free(raw_buf);
-  	unregister_blkdev(MAJOR_NR,"fd");
-  	return -ENXIO;
-  }
-
-  /* initialize variables */
-  motor_on_timer.next = NULL;
-  motor_on_timer.prev = NULL;
-  motor_on_timer.expires = 0;
-  motor_on_timer.data = 0;
-  motor_on_timer.function = motor_on_callback;
-  for (i = 0; i < FD_MAX_UNITS; i++) {
-	  motor_off_timer[i].next = NULL;
-	  motor_off_timer[i].prev = NULL;
-	  motor_off_timer[i].expires = 0;
-	  motor_off_timer[i].data = i|0x80000000;
-	  motor_off_timer[i].function = fd_motor_off;
-	  flush_track_timer[i].next = NULL;
-	  flush_track_timer[i].prev = NULL;
-	  flush_track_timer[i].expires = 0;
-	  flush_track_timer[i].data = i;
-	  flush_track_timer[i].function = flush_track_callback;
-
-	  unit[i].track = -1;
-  }
-
-  post_write_timer.next = NULL;
-  post_write_timer.prev = NULL;
-  post_write_timer.expires = 0;
-  post_write_timer.data = 0;
-  post_write_timer.function = post_write;
+	if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
+		printk("fd: Unable to get major %d for floppy\n",MAJOR_NR);
+		return -EBUSY;
+	}
+
+	if ((raw_buf = (char *)amiga_chip_alloc (RAW_BUF_SIZE)) == NULL) {
+		printk("fd: cannot get chip mem buffer\n");
+		unregister_blkdev(MAJOR_NR,"fd");
+		return -ENOMEM;
+	}
+
+	if (!request_irq(IRQ_AMIGA_DSKBLK, fd_block_done, 0, "floppy_dma", NULL)) {
+		printk("fd: cannot get irq for dma\n");
+		amiga_chip_free(raw_buf);
+		unregister_blkdev(MAJOR_NR,"fd");
+		return -EBUSY;
+	}
+	if (!request_irq(IRQ_AMIGA_CIAA_TB, ms_isr, 0, "floppy_timer", NULL)) {
+		printk("fd: cannot get irq for timer\n");
+		free_irq(IRQ_AMIGA_DSKBLK, NULL);
+		amiga_chip_free(raw_buf);
+		unregister_blkdev(MAJOR_NR,"fd");
+		return -EBUSY;
+	}
+	if (fd_probe_drives() < 1) { /* No usable drives */
+		free_irq(IRQ_AMIGA_CIAA_TB, NULL);
+		free_irq(IRQ_AMIGA_DSKBLK, NULL);
+		amiga_chip_free(raw_buf);
+		unregister_blkdev(MAJOR_NR,"fd");
+		return -ENXIO;
+	}
+
+	/* initialize variables */
+	motor_on_timer.next = NULL;
+	motor_on_timer.prev = NULL;
+	motor_on_timer.expires = 0;
+	motor_on_timer.data = 0;
+	motor_on_timer.function = motor_on_callback;
+	for (i = 0; i < FD_MAX_UNITS; i++) {
+		motor_off_timer[i].next = NULL;
+		motor_off_timer[i].prev = NULL;
+		motor_off_timer[i].expires = 0;
+		motor_off_timer[i].data = i|0x80000000;
+		motor_off_timer[i].function = fd_motor_off;
+		flush_track_timer[i].next = NULL;
+		flush_track_timer[i].prev = NULL;
+		flush_track_timer[i].expires = 0;
+		flush_track_timer[i].data = i;
+		flush_track_timer[i].function = flush_track_callback;
+
+		unit[i].track = -1;
+	}
+
+	post_write_timer.next = NULL;
+	post_write_timer.prev = NULL;
+	post_write_timer.expires = 0;
+	post_write_timer.data = 0;
+	post_write_timer.function = post_write;
   
-  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-  blksize_size[MAJOR_NR] = floppy_blocksizes;
-  blk_size[MAJOR_NR] = floppy_sizes;
-
-  for (i = 0; i < 128; i++)
-	  mfmdecode[i]=255;
-  for (i = 0; i < 16; i++)
-	  mfmdecode[mfmencode[i]]=i;
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blksize_size[MAJOR_NR] = floppy_blocksizes;
+	blk_size[MAJOR_NR] = floppy_sizes;
+
+	for (i = 0; i < 128; i++)
+		mfmdecode[i]=255;
+	for (i = 0; i < 16; i++)
+		mfmdecode[mfmencode[i]]=i;
 
-  /* make sure that disk DMA is enabled */
-  custom.dmacon = DMAF_SETCLR | DMAF_DISK;
+	/* make sure that disk DMA is enabled */
+	custom.dmacon = DMAF_SETCLR | DMAF_DISK;
 
-  /* init ms timer */
-  ciaa.crb = 8; /* one-shot, stop */
+	/* init ms timer */
+	ciaa.crb = 8; /* one-shot, stop */
 
-  (void)do_floppy; /* avoid warning about unused variable */
-  return 0;
+	(void)do_floppy; /* avoid warning about unused variable */
+	return 0;
 }
 
 #ifdef MODULE
@@ -1879,25 +1893,25 @@
 
 int init_module(void)
 {
-  if (!MACH_IS_AMIGA)
-    return -ENXIO;
-  return amiga_floppy_init();
+	if (!MACH_IS_AMIGA)
+		return -ENXIO;
+	return amiga_floppy_init();
 }
 
 void cleanup_module(void)
 {
-int i;
+	int i;
 
-for( i = 0; i < FD_MAX_UNITS; i++)
-  if (unit[i].type->code != FD_NODRIVE)
-    kfree(unit[i].trackbuf);
-free_irq(IRQ_AMIGA_CIAA_TB, NULL);
-free_irq(IRQ_FLOPPY, NULL);
-custom.dmacon = DMAF_DISK; /* disable DMA */
-amiga_chip_free(raw_buf);
-blk_size[MAJOR_NR] = NULL;
-blksize_size[MAJOR_NR] = NULL;
-blk_dev[MAJOR_NR].request_fn = NULL;
-unregister_blkdev(MAJOR_NR, "fd");
+	for( i = 0; i < FD_MAX_UNITS; i++)
+		if (unit[i].type->code != FD_NODRIVE)
+			kfree(unit[i].trackbuf);
+	free_irq(IRQ_AMIGA_CIAA_TB, NULL);
+	free_irq(IRQ_AMIGA_DSKBLK, NULL);
+	custom.dmacon = DMAF_DISK; /* disable DMA */
+	amiga_chip_free(raw_buf);
+	blk_size[MAJOR_NR] = NULL;
+	blksize_size[MAJOR_NR] = NULL;
+	blk_dev[MAJOR_NR].request_fn = NULL;
+	unregister_blkdev(MAJOR_NR, "fd");
 }
 #endif
diff -u --recursive --new-file v2.3.16/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.3.16/linux/drivers/block/floppy.c	Tue Aug 17 10:48:20 1999
+++ linux/drivers/block/floppy.c	Wed Sep  1 15:34:51 1999
@@ -4384,7 +4384,7 @@
 	}
 }
 
-static void __init mod_setup(char *pattern, void (*setup)(char *))
+static void __init mod_setup(char *pattern, int (*setup)(char *))
 {
 	unsigned long i;
 	char c;
diff -u --recursive --new-file v2.3.16/linux/drivers/block/hpt366.c linux/drivers/block/hpt366.c
--- v2.3.16/linux/drivers/block/hpt366.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/hpt366.c	Tue Sep  7 11:23:40 1999
@@ -466,8 +466,8 @@
 	byte ata66 = 0;
 
 	pci_read_config_byte(dev, 0x5a, &ata66);
-	if (dev->rom_address)
-		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE);
+	if (dev->resource[PCI_ROM_RESOURCE].start)
+		pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
 	printk("%s: reg5ah=0x%02x ATA-%s Cable Port%d\n", name, ata66, (ata66 & 0x02) ? "33" : "66", PCI_FUNC(dev->devfn));
 	return dev->irq;
 }
diff -u --recursive --new-file v2.3.16/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.3.16/linux/drivers/block/ide-cd.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ide-cd.c	Thu Sep  2 13:08:19 1999
@@ -1247,20 +1247,10 @@
 
 	/* Figure out how much data to transfer. */
 	thislen = pc->buflen;
-	if (thislen < 0) thislen = -thislen;
 	if (thislen > len) thislen = len;
 
 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
-		/* Check that we want to write. */
-		if (pc->buflen > 0) {
-			printk ("%s: cdrom_pc_intr: Drive wants "
-				"to transfer data the wrong way!\n",
-				drive->name);
-			pc->stat = 1;
-			thislen = 0;
-		}
-
 		/* Transfer the data. */
 		atapi_output_bytes (drive, pc->buffer, thislen);
 
@@ -1274,19 +1264,11 @@
 
 		/* Keep count of how much data we've moved. */
 		pc->buffer += thislen;
-		pc->buflen += thislen;
+		pc->buflen -= thislen;
 	}
 
 	/* Same drill for reading. */
 	else if ((ireason & 3) == 2) {
-		/* Check that we want to read. */
-		if (pc->buflen < 0) {
-			printk ("%s: cdrom_pc_intr: Drive wants to "
-				"transfer data the wrong way!\n",
-				drive->name);
-			pc->stat = 1;
-			thislen = 0;
-		}
 
 		/* Transfer the data. */
 		atapi_input_bytes (drive, pc->buffer, thislen);
@@ -1333,11 +1315,8 @@
 	struct cdrom_info *info = drive->driver_data;
 
 	info->dma = 0;
-
-	len = pc->buflen;
-	if (len < 0) len = -len;
-
 	pc->stat = 0;
+	len = pc->buflen;
 
 	/* Start sending the command to the drive. */
 	cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
@@ -1794,10 +1773,13 @@
 	toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
 
 	/* Now try to get the total cdrom capacity. */
+#if 0
 	stat = cdrom_get_last_written(MKDEV(HWIF(drive)->major,
 				      drive->select.b.unit << PARTN_BITS),
 				     (long *)&toc->capacity);
-	if (stat) stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
+	if (stat)
+#endif
+	stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
 	if (stat) toc->capacity = 0x1fffff;
 
 	HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS]
@@ -1863,7 +1845,7 @@
 	pc.sense_data = reqbuf;
 
 	pc.buffer =  buf;
-	pc.buflen = - buflen;
+	pc.buflen = buflen;
 	pc.c[0] = GPCMD_MODE_SELECT_10;
 	pc.c[1] = 0x10;
 	pc.c[2] = pageno;
@@ -2048,7 +2030,6 @@
 	return cgc->stat;
 }
 
-
 static
 int ide_cdrom_dev_ioctl (struct cdrom_device_info *cdi,
 			 unsigned int cmd, unsigned long arg)
@@ -2977,11 +2958,3 @@
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
-
-
-/*==========================================================================*/
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff -u --recursive --new-file v2.3.16/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.3.16/linux/drivers/block/ll_rw_blk.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/block/ll_rw_blk.c	Sat Sep  4 13:07:19 1999
@@ -26,6 +26,14 @@
 #include <linux/module.h>
 
 /*
+ * MAC Floppy IWM hooks
+ */
+
+#ifdef CONFIG_MAC_FLOPPY_IWM
+extern int mac_floppy_init(void);
+#endif
+
+/*
  * The request-struct contains all necessary data
  * to load a nr of sectors into memory
  */
@@ -809,6 +817,9 @@
 #endif
 #ifdef CONFIG_MAC_FLOPPY
 	swim3_init();
+#endif
+#ifdef CONFIG_BLK_DEV_SWIM_IOP
+	swimiop_init();
 #endif
 #ifdef CONFIG_AMIGA_FLOPPY
 	amiga_floppy_init();
diff -u --recursive --new-file v2.3.16/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.3.16/linux/drivers/block/loop.c	Mon Jul 12 07:49:36 1999
+++ linux/drivers/block/loop.c	Wed Sep  1 15:12:31 1999
@@ -21,6 +21,10 @@
  * Make real block number available to downstream transfer functions, enables
  * CBC (and relatives) mode encryption requiring unique IVs per data block. 
  * Reed H. Petty, rhp@draper.net
+ *
+ * Maximum number of loop devices now dynamic via max_loop module parameter.
+ * Still fixed at 8 devices when compiled into the kernel normally.
+ * Russell Kroll <rkroll@exploits.org> 19990701
  * 
  * Still To Fix:
  * - Advisory locking is ignored here. 
@@ -61,10 +65,11 @@
 #define TIMEOUT_VALUE (6 * HZ)
 #include <linux/blk.h>
 
-#define MAX_LOOP 8
-static struct loop_device loop_dev[MAX_LOOP];
-static int loop_sizes[MAX_LOOP];
-static int loop_blksizes[MAX_LOOP];
+#include <linux/malloc.h>
+static int max_loop = 8;
+static struct loop_device *loop_dev;
+static int *loop_sizes;
+static int *loop_blksizes;
 
 #define FALSE 0
 #define TRUE (!FALSE)
@@ -169,7 +174,7 @@
 	INIT_REQUEST;
 	current_request=CURRENT;
 	CURRENT=current_request->next;
-	if (MINOR(current_request->rq_dev) >= MAX_LOOP)
+	if (MINOR(current_request->rq_dev) >= max_loop)
 		goto error_out;
 	lo = &loop_dev[MINOR(current_request->rq_dev)];
 	if (!lo->lo_dentry || !lo->transfer)
@@ -578,7 +583,7 @@
 		return -ENODEV;
 	}
 	dev = MINOR(inode->i_rdev);
-	if (dev >= MAX_LOOP)
+	if (dev >= max_loop)
 		return -ENODEV;
 	lo = &loop_dev[dev];
 	switch (cmd) {
@@ -615,7 +620,7 @@
 		return -ENODEV;
 	}
 	dev = MINOR(inode->i_rdev);
-	if (dev >= MAX_LOOP) {
+	if (dev >= max_loop) {
 		return -ENODEV;
 	}
 	lo = &loop_dev[dev];
@@ -640,7 +645,7 @@
 		return 0;
 	}
 	dev = MINOR(inode->i_rdev);
-	if (dev >= MAX_LOOP)
+	if (dev >= max_loop)
 		return 0;
 	err = fsync_dev(inode->i_rdev);
 	lo = &loop_dev[dev];
@@ -674,6 +679,8 @@
  */
 #ifdef MODULE
 #define loop_init init_module
+MODULE_PARM(max_loop, "i");
+MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-255)");
 #endif
 
 int loop_register_transfer(struct loop_func_table *funcs)
@@ -690,7 +697,7 @@
 
 	if ((unsigned)number >= MAX_LO_CRYPT)
 		return -EINVAL; 
-	for (lo = &loop_dev[0]; lo < &loop_dev[MAX_LOOP]; lo++) { 
+	for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) { 
 		int type = lo->lo_encrypt_type;
 		if (type == number) { 
 			xfer_funcs[type]->release(lo);
@@ -714,17 +721,46 @@
 		       MAJOR_NR);
 		return -EIO;
 	}
+
+	if ((max_loop < 1) || (max_loop > 255)) {
+		printk (KERN_WARNING "loop: max_loop must be between 1 and 255\n");
+		return -EINVAL;
+	}
+
 #ifndef MODULE
 	printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);
+#else
+	printk(KERN_INFO "loop: enabling %d loop devices\n", max_loop);
 #endif
 
+	loop_dev = kmalloc (max_loop * sizeof(struct loop_device), GFP_KERNEL);
+	if (!loop_dev) {
+		printk (KERN_ERR "loop: Unable to create loop_dev\n");
+		return -ENOMEM;
+	}
+
+	loop_sizes = kmalloc(max_loop * sizeof(int), GFP_KERNEL);
+	if (!loop_sizes) {
+		printk (KERN_ERR "loop: Unable to create loop_sizes\n");
+		kfree (loop_dev);
+		return -ENOMEM;
+	}
+
+	loop_blksizes = kmalloc (max_loop * sizeof(int), GFP_KERNEL);
+	if (!loop_blksizes) {
+		printk (KERN_ERR "loop: Unable to create loop_blksizes\n");
+		kfree (loop_dev);
+		kfree (loop_sizes);
+		return -ENOMEM;
+	}		
+
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-	for (i=0; i < MAX_LOOP; i++) {
+	for (i=0; i < max_loop; i++) {
 		memset(&loop_dev[i], 0, sizeof(struct loop_device));
 		loop_dev[i].lo_number = i;
 	}
-	memset(&loop_sizes, 0, sizeof(loop_sizes));
-	memset(&loop_blksizes, 0, sizeof(loop_blksizes));
+	memset(loop_sizes, 0, max_loop * sizeof(int));
+	memset(loop_blksizes, 0, max_loop * sizeof(int));
 	blk_size[MAJOR_NR] = loop_sizes;
 	blksize_size[MAJOR_NR] = loop_blksizes;
 
@@ -736,5 +772,9 @@
 {
 	if (unregister_blkdev(MAJOR_NR, "loop") != 0)
 		printk(KERN_WARNING "loop: cannot unregister blkdev\n");
+
+	kfree (loop_dev);
+	kfree (loop_sizes);
+	kfree (loop_blksizes);
 }
 #endif
diff -u --recursive --new-file v2.3.16/linux/drivers/block/macide.c linux/drivers/block/macide.c
--- v2.3.16/linux/drivers/block/macide.c	Thu May 13 11:04:54 1999
+++ linux/drivers/block/macide.c	Sat Sep  4 13:07:19 1999
@@ -16,7 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
-#include <linux/zorro.h>
+#include <linux/delay.h>
 #include <linux/ide.h>
 
 #include <asm/machw.h>
@@ -68,64 +68,16 @@
 
 #define MAC_HD_ISR	0x101
 
-	/*
-	 * IDE interrupt glue - seems to be wired to Nubus, Slot C?
-	 * (ROM code disassembly again)
-	 * First try: just use Nubus interrupt for Slot C. Have Nubus code call
-	 * a wrapper to ide_intr that checks the ISR (see above).
-	 * Need to #define IDE_IRQ_NUBUS though.
-	 * Alternative method: set a mac_ide_hook function pointer to the wrapper 
-	 * here and have via_do_nubus call that hook if set. 
-	 *
-	 * Quadra needs the hook, Powerbook can use Nubus slot C. 
-	 * Checking the ISR on Quadra is done by mac_ack_intr (see Amiga code). mac_ide_intr
-	 * mac_ide_intr is obsolete except for providing the hwgroup argument.
-	 */
-
-	/* The Mac hwif data, for passing hwgroup to ide_intr */
-static ide_hwif_t *mac_hwif = NULL;
-
-	/* The function pointer used in the Nubus handler */
-void (*mac_ide_intr_hook)(int, void *, struct pt_regs *) = NULL;
-
-	/*
-	 * Only purpose: feeds the hwgroup to the main IDE handler. 
-	 * Obsolete as soon as Nubus code is fixed WRT pseudo slot C int.
-	 * (should be the case on Powerbooks)
-	 * Alas, second purpose: feed correct irq to IDE handler (I know,
-	 * that's cheating) :-(((
-	 * Fix needed for interrupt code: accept Nubus ints in the regular
-	 * request_irq code, then register Powerbook IDE as Nubus slot C, 
-	 * Quadra as slot F (F for fictious).
-	 */
-void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	ide_intr(mac_hwif->irq, mac_hwif->hwgroup, regs);
-}
-
-    /*
-     *  Check the interrupt status
-     *
-     *  Note: In 2.0 kernels, there have been timing problems with the 
-     *  Powerbook IDE interface (BUSY was asserted too long after the
-     *  interrupt triggered). Result: repeated errors, recalibrate etc. 
-     *  Adding a wait loop to read_intr, write_intr and set_geom_intr
-     *  fixed the problem (waits in read/write_intr were present for Amiga
-     *  already). 
-     *  Powerbooks were not tested with 2.1 due to lack of FPU emulation
-     *  (thanks Apple for using LC040). If the BUSY problem resurfaces in 
-     *  2.1, my best bet would be to add the wait loop right here, afterr
-     *  checking the interrupt register.
-     */
-
-static int mac_ack_intr(ide_hwif_t *hwif)
+static int mac_ack_intr(ide_hwif_t* hwif)
 {
-    unsigned char ch;
+	unsigned char isr;
+	isr = readb(MAC_HD_BASE + MAC_HD_ISR);
+	if (isr & (1<<5)) {
+		writeb(isr & ~(1<<5), MAC_HD_BASE + MAC_HD_ISR);
+		return 1;
+	}
 
-    ch = inb(hwif->io_ports[IDE_IRQ_OFFSET]);
-    if (!(ch & 0x20))
 	return 0;
-    return 1;
 }
 
     /*
@@ -134,34 +86,31 @@
 
 void macide_init(void)
 {
-    hw_regs_t hw;
-    int index = -1;
+	hw_regs_t hw;
+	int index = -1;
 
-    if (MACH_IS_MAC) {
-	switch(macintosh_config->ide_type) {
-	case 0:
-	    break;
+	if (!MACH_IS_MAC || macintosh_config->ide_type == 0)
+		return;
 
+	switch (macintosh_config->ide_type) {
 	case MAC_IDE_QUADRA:
-	    ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets,
-	    		    0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR),
-			    mac_ack_intr, IRQ_MAC_NUBUS);
-	    index = ide_register_hw(&hw, &mac_hwif);
-	    mac_ide_intr_hook = mac_ide_intr;
-	    break;
+		ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets,
+				0, (ide_ioreg_t)(MAC_HD_BASE+MAC_HD_ISR),
+				mac_ack_intr, IRQ_NUBUS_F);
+		index = ide_register_hw(&hw, NULL);
+		break;
 
 	default:
 	    ide_setup_ports(&hw, (ide_ioreg_t)MAC_HD_BASE, macide_offsets,
-	    		    0, 0, NULL, IRQ_MAC_NUBUS);
-	    index = ide_register_hw(&hw, &mac_hwif);
+	    		    0, 0, NULL, IRQ_NUBUS_C);
+	    index = ide_register_hw(&hw, NULL);
 	    break;
 	}
 
         if (index != -1) {
-	    if (macintosh_config->ide_type == MAC_IDE_QUADRA)
-		printk("ide%d: Macintosh Quadra IDE interface\n", index);
-	    else
-		printk("ide%d: Macintosh Powerbook IDE interface\n", index);
+		if (macintosh_config->ide_type == MAC_IDE_QUADRA)
+			printk("ide%d: Macintosh Quadra IDE interface\n", index);
+		else
+			printk("ide%d: Macintosh Powerbook IDE interface\n", index);
 	}
-    }
 }
diff -u --recursive --new-file v2.3.16/linux/drivers/block/swim_iop.c linux/drivers/block/swim_iop.c
--- v2.3.16/linux/drivers/block/swim_iop.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/swim_iop.c	Sat Sep  4 13:07:19 1999
@@ -0,0 +1,674 @@
+/*
+ * Driver for the SWIM (Super Woz Integrated Machine) IOP
+ * floppy controller on the Macintosh IIfx and Quadra 900/950
+ *
+ * Written by Joshua M. Thompson (funaho@jurai.org)
+ * based on the SWIM3 driver (c) 1996 by Paul Mackerras.
+ *
+ * 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.
+ *
+ * 1999-06-12 (jmt) - Initial implementation.
+ */
+
+/*
+ * -------------------
+ * Theory of Operation
+ * -------------------
+ *
+ * Since the SWIM IOP is message-driven we implement a simple request queue
+ * system.  One outstanding request may be queued at any given time (this is
+ * an IOP limitation); only when that request has completed can a new request
+ * be sent.
+ */
+
+/* This has to be defined before some of the #includes below */
+
+#define MAJOR_NR  FLOPPY_MAJOR
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/fd.h>
+#include <linux/blk.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/mac_iop.h>
+#include <asm/swim_iop.h>
+
+#define DRIVER_VERSION "Version 0.1 (1999-06-12)"
+
+#define MAX_FLOPPIES	4
+
+#define IOCTL_MODE_BIT	8
+#define OPEN_WRITE_BIT	16
+
+enum swim_state {
+	idle,
+	available,
+	revalidating,
+	transferring,
+	ejecting
+};
+
+struct floppy_state {
+	enum swim_state state;
+	int	drive_num;	/* device number */
+	int	secpercyl;	/* disk geometry information */
+	int	secpertrack;
+	int	total_secs;
+	int	write_prot;	/* 1 if write-protected, 0 if not, -1 dunno */
+	int	ref_count;
+	struct timer_list timeout;
+	int	ejected;
+	struct wait_queue *wait;
+	int	wanted;
+	int	timeout_pending;
+};
+
+struct swim_iop_req {
+	int	sent;
+	int	complete;
+	__u8	command[32];
+	struct floppy_state *fs;
+	void	(*done)(struct swim_iop_req *);
+};
+
+static struct swim_iop_req *current_req;
+static int floppy_count;
+
+static struct floppy_state floppy_states[MAX_FLOPPIES];
+
+static int floppy_blocksizes[2] = {512,512};
+static int floppy_sizes[2] = {2880,2880};
+
+static char *drive_names[7] = {
+	"not installed",	/* DRV_NONE    */
+	"unknown (1)",		/* DRV_UNKNOWN */
+	"a 400K drive",		/* DRV_400K    */
+	"an 800K drive"		/* DRV_800K    */
+	"unknown (4)",		/* ????        */
+	"an FDHD",		/* DRV_FDHD    */
+	"unknown (6)",		/* ????        */
+	"an Apple HD20"		/* DRV_HD20    */
+};
+
+int swimiop_init(void);
+static void swimiop_init_request(struct swim_iop_req *);
+static int swimiop_send_request(struct swim_iop_req *);
+static void swimiop_receive(struct iop_msg *, struct pt_regs *);
+static void swimiop_status_update(int, struct swim_drvstatus *);
+static int swimiop_eject(struct floppy_state *fs);
+
+static ssize_t floppy_read(struct file *filp, char *buf,
+			   size_t count, loff_t *ppos);
+static ssize_t floppy_write(struct file *filp, const char *buf,
+			    size_t count, loff_t *ppos);
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long param);
+static int floppy_open(struct inode *inode, struct file *filp);
+static int floppy_release(struct inode *inode, struct file *filp);
+static int floppy_check_change(kdev_t dev);
+static int floppy_revalidate(kdev_t dev);
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+		      int interruptible);
+static void release_drive(struct floppy_state *fs);
+static void set_timeout(struct floppy_state *fs, int nticks,
+			void (*proc)(unsigned long));
+static void fd_request_timeout(unsigned long);
+static void do_fd_request(void);
+static void start_request(struct floppy_state *fs);
+
+static struct file_operations floppy_fops = {
+	NULL,			/* lseek */
+	floppy_read,		/* read */
+	floppy_write,		/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	floppy_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	floppy_open,		/* open */
+	NULL,			/* flush */
+	floppy_release,		/* release */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	floppy_check_change,	/* check_media_change */
+	floppy_revalidate,	/* revalidate */
+};
+
+/*
+ * SWIM IOP initialization
+ */
+
+int swimiop_init(void)
+{
+	volatile struct swim_iop_req req;
+	struct swimcmd_status *cmd = (struct swimcmd_status *) &req.command[0];
+	struct swim_drvstatus *ds = &cmd->status;
+	struct floppy_state *fs;
+	int i;
+
+	current_req = NULL;
+	floppy_count = 0;
+
+	if (!iop_ism_present) return -ENODEV;
+
+	if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+		printk(KERN_ERR "SWIM-IOP: Unable to get major %d for floppy\n",
+		       MAJOR_NR);
+		return -EBUSY;
+	}
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blksize_size[MAJOR_NR] = floppy_blocksizes;
+	blk_size[MAJOR_NR] = floppy_sizes;
+
+	printk("SWIM-IOP: %s by Joshua M. Thompson (funaho@jurai.org)\n",
+		DRIVER_VERSION);
+
+	if (iop_listen(SWIM_IOP, SWIM_CHAN, swimiop_receive, "SWIM") != 0) {
+		printk(KERN_ERR "SWIM-IOP: IOP channel already in use; can't initialize.\n");
+		return -EBUSY;
+	}
+
+	printk(KERN_ERR "SWIM_IOP: probing for installed drives.\n");
+
+	for (i = 0 ; i < MAX_FLOPPIES ; i++) {
+		memset(&floppy_states[i], 0, sizeof(struct floppy_state));
+		fs = &floppy_states[floppy_count];
+
+		swimiop_init_request(&req);
+		cmd->code = CMD_STATUS;
+		cmd->drive_num = i + 1;
+		if (swimiop_send_request(&req) != 0) continue;
+		while (!req.complete);
+		if (cmd->error != 0) {
+			printk(KERN_ERR "SWIM-IOP: probe on drive %d returned error %d\n", i, (uint) cmd->error);
+			continue;
+		}
+		if (ds->installed != 0x01) continue;
+		printk("SWIM-IOP: drive %d is %s (%s, %s, %s, %s)\n", i,
+			drive_names[ds->info.type],
+			ds->info.external? "ext" : "int",
+			ds->info.scsi? "scsi" : "floppy",
+			ds->info.fixed? "fixed" : "removable",
+			ds->info.secondary? "secondary" : "primary");
+		swimiop_status_update(floppy_count, ds);
+		fs->state = idle;
+
+		init_timer(&fs->timeout);
+		floppy_count++;
+	}
+	printk("SWIM-IOP: detected %d installed drives.\n", floppy_count);
+
+	do_floppy = NULL;
+
+	return 0;
+}
+
+static void swimiop_init_request(struct swim_iop_req *req)
+{
+	req->sent = 0;
+	req->complete = 0;
+	req->done = NULL;
+}
+
+static int swimiop_send_request(struct swim_iop_req *req)
+{
+	unsigned long cpu_flags;
+	int err;
+
+	/* It's doubtful an interrupt routine would try to send */
+	/* a SWIM request, but I'd rather play it safe here.    */
+
+	save_flags(cpu_flags);
+	cli();
+
+	if (current_req != NULL) {
+		restore_flags(cpu_flags);
+		return -ENOMEM;
+	}
+
+	current_req = req;
+
+	/* Interrupts should be back on for iop_send_message() */
+
+	restore_flags(cpu_flags);
+
+	err = iop_send_message(SWIM_IOP, SWIM_CHAN, (void *) req,
+				sizeof(req->command), (__u8 *) &req->command[0],
+				swimiop_receive);
+
+	/* No race condition here; we own current_req at this point */
+
+	if (err) {
+		current_req = NULL;
+	} else {
+		req->sent = 1;
+	}
+	return err;
+}
+
+/*
+ * Receive a SWIM message from the IOP.
+ *
+ * This will be called in two cases:
+ *
+ * 1. A message has been successfully sent to the IOP.
+ * 2. An unsolicited message was received from the IOP.
+ */
+
+void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs)
+{
+	struct swim_iop_req *req;
+	struct swimmsg_status *sm;
+	struct swim_drvstatus *ds;
+
+	req = current_req;
+
+	switch(msg->status) {
+		case IOP_MSGSTATUS_COMPLETE:
+			memcpy(&req->command[0], &msg->reply[0], sizeof(req->command));
+			req->complete = 1;
+			if (req->done) (*req->done)(req);
+			current_req = NULL;
+			break;
+		case IOP_MSGSTATUS_UNSOL:
+			sm = (struct swimmsg_status *) &msg->message[0];
+			ds = &sm->status;
+			swimiop_status_update(sm->drive_num, ds);
+			iop_complete_message(msg);
+			break;
+	}
+}
+
+static void swimiop_status_update(int drive_num, struct swim_drvstatus *ds)
+{
+	struct floppy_state *fs = &floppy_states[drive_num];
+
+	fs->write_prot = (ds->write_prot == 0x80);
+	if ((ds->disk_in_drive != 0x01) && (ds->disk_in_drive != 0x02)) {
+		fs->ejected = 1;
+	} else {
+		fs->ejected = 0;
+	}
+	switch(ds->info.type) {
+		case DRV_400K:
+			fs->secpercyl = 10;
+			fs->secpertrack = 10;
+			fs->total_secs = 800;
+			break;
+		case DRV_800K:
+			fs->secpercyl = 20;
+			fs->secpertrack = 10;
+			fs->total_secs = 1600;
+			break;
+		case DRV_FDHD:
+			fs->secpercyl = 36;
+			fs->secpertrack = 18;
+			fs->total_secs = 2880;
+			break;
+		default:
+			fs->secpercyl = 0;
+			fs->secpertrack = 0;
+			fs->total_secs = 0;
+			break;
+	}
+}
+
+static int swimiop_eject(struct floppy_state *fs)
+{
+	int err, n;
+	struct swim_iop_req req;
+	struct swimcmd_eject *cmd = (struct swimcmd_eject *) &req.command[0];
+
+	err = grab_drive(fs, ejecting, 1);
+	if (err) return err;
+
+	swimiop_init_request(&req);
+	cmd->code = CMD_EJECT;
+	cmd->drive_num = fs->drive_num;
+	err = swimiop_send_request(&req);
+	if (err) {
+		release_drive(fs);
+		return err;
+	}
+	for (n = 2*HZ; n > 0; --n) {
+		if (req.complete) break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(1);
+	}
+	release_drive(fs);
+	return cmd->error;
+}
+
+static ssize_t floppy_read(struct file *filp, char *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct floppy_state *fs;
+	int devnum = MINOR(inode->i_rdev);
+
+	if (devnum >= floppy_count)
+		return -ENODEV;
+		
+	fs = &floppy_states[devnum];
+	if (fs->ejected)
+		return -ENXIO;
+	return block_read(filp, buf, count, ppos);
+}
+
+static ssize_t floppy_write(struct file * filp, const char * buf,
+			    size_t count, loff_t *ppos)
+{
+	struct inode * inode = filp->f_dentry->d_inode;
+	struct floppy_state *fs;
+	int devnum = MINOR(inode->i_rdev);
+
+	if (devnum >= floppy_count)
+		return -ENODEV;
+	check_disk_change(inode->i_rdev);
+	fs = &floppy_states[devnum];
+	if (fs->ejected)
+		return -ENXIO;
+	if (fs->write_prot)
+		return -EROFS;
+	return block_write(filp, buf, count, ppos);
+}
+
+static struct floppy_struct floppy_type =
+	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };	/*  7 1.44MB 3.5"   */
+
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long param)
+{
+	struct floppy_state *fs;
+	int err;
+	int devnum = MINOR(inode->i_rdev);
+
+	if (devnum >= floppy_count)
+		return -ENODEV;
+		
+	if (((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))) ||
+	    ((cmd & 0x80) && !suser()))
+		return -EPERM;
+
+	fs = &floppy_states[devnum];
+
+	switch (cmd) {
+	case FDEJECT:
+		if (fs->ref_count != 1)
+			return -EBUSY;
+		err = swimiop_eject(fs);
+		return err;
+	case FDGETPRM:
+	        err = copy_to_user((void *) param, (void *) &floppy_type,
+				   sizeof(struct floppy_struct));
+		return err;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int floppy_open(struct inode *inode, struct file *filp)
+{
+	struct floppy_state *fs;
+	int err;
+	int devnum = MINOR(inode->i_rdev);
+
+	if (devnum >= floppy_count)
+		return -ENODEV;
+	if (filp == 0)
+		return -EIO;
+		
+	fs = &floppy_states[devnum];
+	err = 0;
+	if (fs->ref_count == -1 || filp->f_flags & O_EXCL) return -EBUSY;
+
+	if (err == 0 && (filp->f_flags & O_NDELAY) == 0
+	    && (filp->f_mode & 3)) {
+		check_disk_change(inode->i_rdev);
+		if (fs->ejected)
+			err = -ENXIO;
+	}
+
+	if (err == 0 && (filp->f_mode & 2)) {
+		if (fs->write_prot)
+			err = -EROFS;
+	}
+
+	if (err) return err;
+
+	if (filp->f_flags & O_EXCL)
+		fs->ref_count = -1;
+	else
+		++fs->ref_count;
+
+	/* Allow ioctls if we have write-permissions even if read-only open */
+	if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
+		filp->f_mode |= IOCTL_MODE_BIT;
+	if (filp->f_mode & 2)
+		filp->f_mode |= OPEN_WRITE_BIT;
+
+	return 0;
+}
+
+static int floppy_release(struct inode *inode, struct file *filp)
+{
+	struct floppy_state *fs;
+	int devnum = MINOR(inode->i_rdev);
+
+	if (devnum >= floppy_count)
+		return -ENODEV;
+
+	/*
+	 * If filp is NULL, we're being called from blkdev_release
+	 * or after a failed mount attempt.  In the former case the
+	 * device has already been sync'ed, and in the latter no
+	 * sync is required.  Otherwise, sync if filp is writable.
+	 */
+	if (filp && (filp->f_mode & (2 | OPEN_WRITE_BIT)))
+		block_fsync (filp, filp->f_dentry);
+
+	fs = &floppy_states[devnum];
+	if (fs->ref_count > 0) fs->ref_count--;
+	return 0;
+}
+
+static int floppy_check_change(kdev_t dev)
+{
+	struct floppy_state *fs;
+	int devnum = MINOR(dev);
+
+	if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count))
+		return 0;
+		
+	fs = &floppy_states[devnum];
+	return fs->ejected;
+}
+
+static int floppy_revalidate(kdev_t dev)
+{
+	struct floppy_state *fs;
+	int devnum = MINOR(dev);
+
+	if (MAJOR(dev) != MAJOR_NR || (devnum >= floppy_count))
+		return 0;
+
+	fs = &floppy_states[devnum];
+
+	grab_drive(fs, revalidating, 0);
+	/* yadda, yadda */
+	release_drive(fs);
+
+	return 0;
+}
+
+static void floppy_off(unsigned int nr)
+{
+}
+
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+		      int interruptible)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (fs->state != idle) {
+		++fs->wanted;
+		while (fs->state != available) {
+			if (interruptible && signal_pending(current)) {
+				--fs->wanted;
+				restore_flags(flags);
+				return -EINTR;
+			}
+			interruptible_sleep_on(&fs->wait);
+		}
+		--fs->wanted;
+	}
+	fs->state = state;
+	restore_flags(flags);
+	return 0;
+}
+
+static void release_drive(struct floppy_state *fs)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	fs->state = idle;
+	start_request(fs);
+	restore_flags(flags);
+}
+
+static void set_timeout(struct floppy_state *fs, int nticks,
+			void (*proc)(unsigned long))
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	if (fs->timeout_pending)
+		del_timer(&fs->timeout);
+	fs->timeout.expires = jiffies + nticks;
+	fs->timeout.function = proc;
+	fs->timeout.data = (unsigned long) fs;
+	add_timer(&fs->timeout);
+	fs->timeout_pending = 1;
+	restore_flags(flags);
+}
+
+static void do_fd_request(void)
+{
+	int i;
+
+	for (i = 0 ; i < floppy_count ; i++) {
+		start_request(&floppy_states[i]);
+	}
+}
+
+static void fd_request_complete(struct swim_iop_req *req)
+{
+	struct floppy_state *fs = req->fs;
+	struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req->command[0];
+
+	del_timer(&fs->timeout);
+	fs->timeout_pending = 0;
+	fs->state = idle;
+	if (cmd->error) {
+		printk(KERN_ERR "SWIM-IOP: error %d on read/write request.\n", cmd->error);
+		end_request(0);
+	} else {
+		CURRENT->sector += cmd->num_blocks;
+		CURRENT->current_nr_sectors -= cmd->num_blocks;
+		if (CURRENT->current_nr_sectors <= 0) {
+			end_request(1);
+			return;
+		}
+	}
+	start_request(fs);
+}
+
+static void fd_request_timeout(unsigned long data)
+{
+	struct floppy_state *fs = (struct floppy_state *) data;
+
+	fs->timeout_pending = 0;
+	end_request(0);
+	fs->state = idle;
+}
+
+static void start_request(struct floppy_state *fs)
+{
+	volatile struct swim_iop_req req;
+	struct swimcmd_rw *cmd = (struct swimcmd_rw *) &req.command[0];
+
+	if (fs->state == idle && fs->wanted) {
+		fs->state = available;
+		wake_up(&fs->wait);
+		return;
+	}
+	while (CURRENT && fs->state == idle) {
+		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+			panic(DEVICE_NAME ": request list destroyed");
+		if (CURRENT->bh && !buffer_locked(CURRENT->bh))
+			panic(DEVICE_NAME ": block not locked");
+#if 0
+		printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+		       kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd,
+		       CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer);
+		printk("           rq_status=%d errors=%d current_nr_sectors=%ld\n",
+		       CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
+#endif
+
+		if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
+			end_request(0);
+			continue;
+		}
+		if (CURRENT->current_nr_sectors == 0) {
+			end_request(1);
+			continue;
+		}
+		if (fs->ejected) {
+			end_request(0);
+			continue;
+		}
+
+		swimiop_init_request(&req);
+		req.fs = fs;
+		req.done = fd_request_complete;
+
+		if (CURRENT->cmd == WRITE) {
+			if (fs->write_prot) {
+				end_request(0);
+				continue;
+			}
+			cmd->code = CMD_WRITE;
+		} else {
+			cmd->code = CMD_READ;
+
+		}
+		cmd->drive_num = fs->drive_num;
+		cmd->buffer = CURRENT->buffer;
+		cmd->first_block = CURRENT->sector;
+		cmd->num_blocks = CURRENT->current_nr_sectors;
+
+		if (swimiop_send_request(&req)) {
+			end_request(0);
+			continue;
+		}
+
+		set_timeout(fs, HZ*CURRENT->current_nr_sectors,
+				fd_request_timeout);
+
+		fs->state = transferring;
+	}
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.3.16/linux/drivers/cdrom/cdrom.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/cdrom/cdrom.c	Thu Sep  2 13:08:19 1999
@@ -473,7 +473,8 @@
 		    /* give people a warning shot, now that CDO_CHECK_TYPE
 		       is the default case! */
 		    cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
-		    cdinfo(CD_WARNING, "pid %d is buggy!\n", (unsigned int)current->pid); 
+		    cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
+					(unsigned int)current->pid); 
 		    ret=-EMEDIUMTYPE;
 		    goto clean_up_and_return;
 		}
@@ -835,7 +836,7 @@
 	case DVD_HOST_SEND_CHALLENGE:
 		cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_CHALLENGE\n"); 
 		setup_send_key (&cgc, ai->hsc.agid, 1);
-		cgc.buflen = -(cgc.cmd[9] = 16);
+		cgc.buflen = cgc.cmd[9] = 16;
 		buf[1] = 14;
 		copy_chal (&buf[4], ai->hsc.chal);
 
@@ -848,7 +849,7 @@
 	case DVD_HOST_SEND_KEY2:
 		cdinfo(CD_DO_IOCTL, "entering DVD_HOST_SEND_KEY2\n"); 
 		setup_send_key (&cgc, ai->hsk.agid, 3);
-		cgc.buflen = -(cgc.cmd[9] = 12);
+		cgc.buflen = cgc.cmd[9] = 12;
 		buf[1] = 10;
 		copy_key (&buf[4], ai->hsk.key);
 
@@ -1080,13 +1081,8 @@
 	
 	cgc->cmd[0] = GPCMD_MODE_SELECT_10;
 	cgc->cmd[1] = 0x10;		/* PF */
-
-	/* generic_packet() wants the length as seen from the drive, i.e.
-	   it will transfer data _to_ us. The CD-ROM wants the absolute
-	   value, however. */
-	cgc->cmd[7] = (-cgc->buflen) >> 8;
-	cgc->cmd[8] = (-cgc->buflen) & 0xff;
-
+	cgc->cmd[7] = cgc->buflen >> 8;
+	cgc->cmd[8] = cgc->buflen & 0xff;
 	return cdo->generic_packet(cdi, cgc);
 }
 
@@ -1734,7 +1730,6 @@
 		memset(buffer, 0, 3);
 
 		/* set volume */
-		cgc.buflen = -cgc.buflen;
 		cgc.buffer = buffer;
 		return cdrom_mode_select(cdi, &cgc);
 		}
@@ -2234,12 +2229,3 @@
 }
 
 #endif /* endif MODULE */
-
-
-
-/*
- * Local variables:
- * comment-column: 40
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DCPU=486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cdrom.o cdrom.c"
- * End:
- */
diff -u --recursive --new-file v2.3.16/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.3.16/linux/drivers/char/Config.in	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/Config.in	Thu Sep  2 10:02:32 1999
@@ -69,7 +69,9 @@
   dep_tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
   dep_tristate 'Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
   dep_tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
-  dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+  if [ "$CONFIG_PPC" = "y" ; then
+    dep_tristate 'Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+  fi
 fi
 
 tristate 'Mouse Support (not serial and bus mice)' CONFIG_MOUSE
diff -u --recursive --new-file v2.3.16/linux/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- v2.3.16/linux/drivers/char/amigamouse.c	Mon Aug  2 09:54:29 1999
+++ linux/drivers/char/amigamouse.c	Sat Sep  4 13:08:32 1999
@@ -58,7 +58,7 @@
 
 #include "busmouse.h"
 
-#if 0
+#if AMIGA_OLD_INT
 #define AMI_MSE_INT_ON()	mouseint_allowed = 1
 #define AMI_MSE_INT_OFF()	mouseint_allowed = 0
 static int mouseint_allowed;
@@ -75,7 +75,7 @@
 
 	unsigned short joy0dat, potgor;
 
-#if 0
+#if AMIGA_OLD_INT
 	if(!mouseint_allowed)
 		return;
 	AMI_MSE_INT_OFF();
@@ -136,7 +136,7 @@
 
 
 	busmouse_add_movementbuttons(msedev, dx, -dy, buttons);
-#if 0
+#if AMIGA_OLD_INT
 	AMI_MSE_INT_ON();
 #endif
 }
@@ -148,7 +148,7 @@
 static int release_mouse(struct inode * inode, struct file * file)
 {
 	free_irq(IRQ_AMIGA_VERTB, mouse_interrupt);
-#if 0
+#if AMIGA_OLD_INT
 	AMI_MSE_INT_OFF();
 #endif
 	MOD_DEC_USE_COUNT;
@@ -173,7 +173,7 @@
 	}
 
 	MOD_INC_USE_COUNT;
-#if 0
+#if AMIGA_OLD_INT
 	AMI_MSE_INT_ON();
 #endif
 	return 0;
@@ -189,7 +189,7 @@
 		return -ENODEV;
 
 	custom.joytest = 0;	/* reset counters */
-#if 0
+#if AMIGA_OLD_INT
 	AMI_MSE_INT_OFF();
 #endif
 	msedev = register_busmouse(&amigamouse);
@@ -200,15 +200,12 @@
 	return msedev < 0 ? msedev : 0;
 }
 
-#ifdef MODULE
-
-int init_module(void)
+void __exit amiga_mouse_exit(void)
 {
-	return amiga_mouse_init();
+	unregister_busmouse(msedev);
 }
 
-void cleanup_module(void)
-{
-	unregsiter_busmouse(msedev);
-}
+#ifdef MODULE
+module_init(amiga_mouse_init)
+module_exit(amiga_mouse_exit)
 #endif
diff -u --recursive --new-file v2.3.16/linux/drivers/char/applicom.c linux/drivers/char/applicom.c
--- v2.3.16/linux/drivers/char/applicom.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/applicom.c	Thu Sep  2 10:19:06 1999
@@ -182,7 +182,7 @@
 
 #endif /* MODULE */
 
-__initfunc(int applicom_init(void))
+int __init applicom_init(void)
 {
 	int i, numisa=0;
 	struct pci_dev *dev = NULL;
diff -u --recursive --new-file v2.3.16/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v2.3.16/linux/drivers/char/atarimouse.c	Mon Aug  2 09:54:29 1999
+++ linux/drivers/char/atarimouse.c	Sat Sep  4 13:08:32 1999
@@ -43,12 +43,12 @@
 
 /*    ikbd_mouse_disable(); */
 
-    buttons = ((buf[0] & 1 ? 1 : 0)
-	       | (buf[0] & 2 ? 4 : 0)
+    buttons = ((buf[0] & 1)
+	       | ((buf[0] & 2) << 1)
 	       | (atari_mouse_buttons & 2));
     atari_mouse_buttons = buttons;
 
-    busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons);
+    busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7);
 /*    ikbd_mouse_rel_pos(); */
 }
 
diff -u --recursive --new-file v2.3.16/linux/drivers/char/istallion.c linux/drivers/char/istallion.c
--- v2.3.16/linux/drivers/char/istallion.c	Mon Aug  9 10:23:09 1999
+++ linux/drivers/char/istallion.c	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	istallion.c  -- stallion intelligent multiport serial driver.
  *
  *	Copyright (C) 1996-1999  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	This code is loosely based on the Linux serial driver, written by
  *	Linus Torvalds, Theodore T'so and others.
@@ -167,7 +167,7 @@
  */
 static char	*stli_drvtitle = "Stallion Intelligent Multiport Serial Driver";
 static char	*stli_drvname = "istallion";
-static char	*stli_drvversion = "5.5.1";
+static char	*stli_drvversion = "5.6.0";
 static char	*stli_serialname = "ttyE";
 static char	*stli_calloutname = "cue";
 
@@ -186,7 +186,7 @@
  *	is already swapping a shared buffer won't make things any worse.
  */
 static char			*stli_tmpwritebuf = (char *) NULL;
-static struct semaphore		stli_tmpwritesem = MUTEX;
+static DECLARE_MUTEX(stli_tmpwritesem);
 
 #define	STLI_TXBUFSIZE		4096
 
@@ -3375,6 +3375,9 @@
 		portp->closing_wait = 30 * HZ;
 		portp->tqhangup.routine = stli_dohangup;
 		portp->tqhangup.data = portp;
+		init_waitqueue_head(&portp->open_wait);
+		init_waitqueue_head(&portp->close_wait);
+		init_waitqueue_head(&portp->raw_wait);
 		portp->normaltermios = stli_deftermios;
 		portp->callouttermios = stli_deftermios;
 		panelport++;
@@ -4671,16 +4674,16 @@
 
 #if DEBUG
 	printk("%s(%d): BAR[]=%x,%x,%x,%x\n", __FILE__, __LINE__,
-		devp->base_address[0], devp->base_address[1],
-		devp->base_address[2], devp->base_address[3]);
+		devp->resource[0].start, devp->resource[1].start,
+		devp->resource[2].start, devp->resource[3].start);
 #endif
 
 /*
  *	We have all resources from the board, so lets setup the actual
  *	board structure now.
  */
-	brdp->iobase = (devp->base_address[3] & PCI_BASE_ADDRESS_IO_MASK);
-	brdp->memaddr = (devp->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+	brdp->iobase = (devp->resource[3].start & PCI_BASE_ADDRESS_IO_MASK);
+	brdp->memaddr = (devp->resource[2].start & PCI_BASE_ADDRESS_MEM_MASK);
 	stli_brdinit(brdp);
 
 	return(0);
diff -u --recursive --new-file v2.3.16/linux/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- v2.3.16/linux/drivers/char/n_r3964.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/n_r3964.c	Thu Sep  2 09:24:11 1999
@@ -52,7 +52,6 @@
 #include <linux/malloc.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
-#include <linux/sched.h>    /* to get the struct task_struct */
 #include <linux/string.h>   /* used in new tty drivers */
 #include <linux/signal.h>   /* used in new tty drivers */
 #include <linux/ioctl.h>
@@ -221,7 +220,7 @@
 
 #endif /* MODULE */
 
-__initfunc(static int r3964_init(void))
+static int __init r3964_init(void)
 {
    int status;
    
diff -u --recursive --new-file v2.3.16/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.3.16/linux/drivers/char/serial.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/char/serial.c	Wed Sep  1 15:34:01 1999
@@ -146,13 +146,12 @@
 #ifdef MODVERSIONS
 #include <linux/modversions.h>
 #endif
-#include <linux/module.h>
 #else /* !NEW_MODULES */
 #ifdef MODVERSIONS
 #define MODULE
 #endif
-#include <linux/module.h>
 #endif /* NEW_MODULES */
+#include <linux/module.h>
 
 #ifdef LOCAL_HEADERS
 #include "serial_local.h"
diff -u --recursive --new-file v2.3.16/linux/drivers/char/stallion.c linux/drivers/char/stallion.c
--- v2.3.16/linux/drivers/char/stallion.c	Thu Aug  5 14:34:02 1999
+++ linux/drivers/char/stallion.c	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	stallion.c  -- stallion multiport serial driver.
  *
  *	Copyright (C) 1996-1999  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	This code is loosely based on the Linux serial driver, written by
  *	Linus Torvalds, Theodore T'so and others.
@@ -135,7 +135,7 @@
  */
 static char	*stl_drvtitle = "Stallion Multiport Serial Driver";
 static char	*stl_drvname = "stallion";
-static char	*stl_drvversion = "5.5.1";
+static char	*stl_drvversion = "5.6.0";
 static char	*stl_serialname = "ttyE";
 static char	*stl_calloutname = "cue";
 
@@ -2294,7 +2294,7 @@
 			break;
 	}
 	if (i >= stl_numintrs) {
-		if (request_irq(irq, stl_intr, SA_INTERRUPT, name, NULL) != 0) {
+		if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) {
 			printk("STALLION: failed to register interrupt "
 				"routine for %s irq=%d\n", name, irq);
 			rc = -ENODEV;
@@ -2348,6 +2348,8 @@
 		portp->callouttermios = stl_deftermios;
 		portp->tqueue.routine = stl_offintr;
 		portp->tqueue.data = portp;
+		init_waitqueue_head(&portp->open_wait);
+		init_waitqueue_head(&portp->close_wait);
 		portp->stats.brd = portp->brdnr;
 		portp->stats.panel = portp->panelnr;
 		portp->stats.port = portp->portnr;
@@ -2780,7 +2782,7 @@
 
 #if DEBUG
 	printk("stl_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n", brdtype,
-		dev->bus->number, dev->devfn);
+		devp->bus->number, devp->devfn);
 #endif
 
 	if ((brdp = stl_allocbrd()) == (stlbrd_t *) NULL)
@@ -2798,8 +2800,8 @@
  */
 #if DEBUG
 	printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
-		devp->base_address[0], devp->base_address[1],
-		devp->base_address[2], devp->base_address[3], devp->irq);
+		devp->resource[0].start, devp->resource[1].start,
+		devp->resource[2].start, devp->resource[3].start, devp->irq);
 #endif
 
 /*
@@ -2808,21 +2810,21 @@
  */
 	switch (brdtype) {
 	case BRD_ECHPCI:
-		brdp->ioaddr2 = (devp->base_address[0] &
+		brdp->ioaddr2 = (devp->resource[0].start &
 			PCI_BASE_ADDRESS_IO_MASK);
-		brdp->ioaddr1 = (devp->base_address[1] &
+		brdp->ioaddr1 = (devp->resource[1].start &
 			PCI_BASE_ADDRESS_IO_MASK);
 		break;
 	case BRD_ECH64PCI:
-		brdp->ioaddr2 = (devp->base_address[2] &
+		brdp->ioaddr2 = (devp->resource[2].start &
 			PCI_BASE_ADDRESS_IO_MASK);
-		brdp->ioaddr1 = (devp->base_address[1] &
+		brdp->ioaddr1 = (devp->resource[1].start &
 			PCI_BASE_ADDRESS_IO_MASK);
 		break;
 	case BRD_EASYIOPCI:
-		brdp->ioaddr1 = (devp->base_address[2] &
+		brdp->ioaddr1 = (devp->resource[2].start &
 			PCI_BASE_ADDRESS_IO_MASK);
-		brdp->ioaddr2 = (devp->base_address[1] &
+		brdp->ioaddr2 = (devp->resource[1].start &
 			PCI_BASE_ADDRESS_IO_MASK);
 		break;
 	default:
@@ -4209,6 +4211,7 @@
 		if ((tty == (struct tty_struct *) NULL) ||
 		    (tty->flip.char_buf_ptr == (char *) NULL) ||
 		    ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+			len = MIN(len, sizeof(stl_unwanted));
 			outb((RDSR + portp->uartaddr), ioaddr);
 			insb((ioaddr + EREG_DATA), &stl_unwanted[0], len);
 			portp->stats.rxlost += len;
@@ -5175,6 +5178,7 @@
 		if ((tty == (struct tty_struct *) NULL) ||
 		    (tty->flip.char_buf_ptr == (char *) NULL) ||
 		    ((buflen = TTY_FLIPBUF_SIZE - tty->flip.count) == 0)) {
+			len = MIN(len, sizeof(stl_unwanted));
 			outb(GRXFIFO, (ioaddr + XP_ADDR));
 			insb((ioaddr + XP_DATA), &stl_unwanted[0], len);
 			portp->stats.rxlost += len;
diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.3.16/linux/drivers/i2o/i2o_block.c	Thu Aug  5 15:04:52 1999
+++ linux/drivers/i2o/i2o_block.c	Tue Sep  7 10:22:12 1999
@@ -17,10 +17,14 @@
  *	Fixes:
  *		Steve Ralston:	Multiple device handling error fixes,
  *				Added a queue depth.
- *
- *	Todo:
- *		64bit cleanness.
- *		Remove the queue walk. We can do that better.
+ *		Alan Cox:	FC920 has an rmw bug. Dont or in the
+ *				end marker.
+ *				Removed queue walk, fixed for 64bitness.
+ *	To do:
+ *		Multiple majors
+ *		Serial number scanning to find duplicates for FC multipathing
+ *		Set the new max_sectors according to max message size
+ *		Use scatter gather chains for bigger I/O sizes
  */
 
 #include <linux/major.h>
@@ -52,7 +56,7 @@
 
 #define MAX_I2OB	16
 
-#define MAX_I2OB_DEPTH	8
+#define MAX_I2OB_DEPTH	32
 
 /*
  *	Some of these can be made smaller later
@@ -80,6 +84,20 @@
 };
 
 /*
+ *	FIXME:
+ *	We should cache align these to avoid ping-ponging lines on SMP
+ *	boxes under heavy I/O load...
+ */
+ 
+struct i2ob_request
+{
+	struct i2ob_request *next;
+	struct request *req;
+	int num;
+};
+
+
+/*
  *	Each I2O disk is one of these.
  */
 
@@ -89,6 +107,8 @@
 static struct gendisk i2ob_gendisk;	/* Declared later */
 
 static atomic_t queue_depth;		/* For flow control later on */
+static struct i2ob_request i2ob_queue[MAX_I2OB_DEPTH+1];
+static struct i2ob_request *i2ob_qhead;
 
 #define DEBUG( s )
 /* #define DEBUG( s ) printk( s ) 
@@ -112,13 +132,14 @@
  *	Turn a Linux block request into an I2O block read/write.
  */
 
-static int i2ob_send(u32 m, struct i2ob_device *dev, struct request *req, u32 base, int unit)
+static int i2ob_send(u32 m, struct i2ob_device *dev, struct i2ob_request *ireq, u32 base, int unit)
 {
 	struct i2o_controller *c = dev->controller;
 	int tid = dev->tid;
 	u32 *msg;
 	u32 *mptr;
 	u64 offset;
+	struct request *req = ireq->req;
 	struct buffer_head *bh = req->bh;
 	static int old_qd = 2;
 	int count = req->nr_sectors<<9;
@@ -130,7 +151,7 @@
 	msg = bus_to_virt(c->mem_offset + m);
 	
 	msg[2] = i2ob_context|(unit<<8);
-	msg[3] = (u32)req;	/* 64bit issue again here */
+	msg[3] = ireq->num;
 	msg[5] = req->nr_sectors << 9;
 	
 	/* This can be optimised later - just want to be sure its right for
@@ -147,7 +168,16 @@
 		msg[4] = 1<<16;	
 		while(bh!=NULL)
 		{
-			*mptr++ = 0x10000000|(bh->b_size);
+			/*
+			 *	Its best to do this in one not or it in
+			 *	later. mptr is in PCI space so fast to write
+			 *	sucky to read.
+			 */
+			if(bh->b_reqnext)
+				*mptr++ = 0x10000000|(bh->b_size);
+			else
+				*mptr++ = 0xD0000000|(bh->b_size);
+	
 			*mptr++ = virt_to_bus(bh->b_data);
 			count -= bh->b_size;
 			bh = bh->b_reqnext;
@@ -159,13 +189,15 @@
 		msg[4] = 1<<16;
 		while(bh!=NULL)
 		{
-			*mptr++ = 0x14000000|(bh->b_size);
+			if(bh->b_reqnext)
+				*mptr++ = 0x14000000|(bh->b_size);
+			else
+				*mptr++ = 0xD4000000|(bh->b_size);
 			count -= bh->b_size;
 			*mptr++ = virt_to_bus(bh->b_data);
 			bh = bh->b_reqnext;
 		}
 	}
-	mptr[-2]|= 0xC0000000;
 	msg[0] = I2O_MESSAGE_SIZE(mptr-msg) | SGL_OFFSET_8;
 	
 	if(req->current_nr_sectors > 8)
@@ -187,29 +219,14 @@
 
 /*
  *	Remove a request from the _locked_ request list. We update both the
- *	list chain and if this is the last item the tail pointer.
+ *	list chain and if this is the last item the tail pointer. Caller
+ *	must hold the lock.
  */
  
-static void i2ob_unhook_request(struct i2ob_device *dev, struct request *req)
+static inline void i2ob_unhook_request(struct i2ob_request *ireq)
 {
-	struct request **p = &dev->head;
-	struct request *nt = NULL;
-	static int crap = 0;
-	
-	while(*p!=NULL)
-	{
-		if(*p==req)
-		{
-			if(dev->tail==req)
-				dev->tail = nt;
-			*p=req->next;
-			return;
-		}
-		nt=*p;
-		p=&(nt->next);
-	}
-	if(!crap++)
-		printk("i2o_block: request queue corrupt!\n");
+	ireq->next = i2ob_qhead;
+	i2ob_qhead = ireq;
 }
 
 /*
@@ -223,12 +240,20 @@
 	 * to this request have been marked updated and
 	 * unlocked.
 	 */
-	while (end_that_request_first( req, !req->errors, "i2o block" ));
+
+//	printk("ending request %p: ", req);
+	while (end_that_request_first( req, !req->errors, "i2o block" ))
+	{
+//		printk(" +\n");
+	}
 
 	/*
 	 * It is now ok to complete the request.
 	 */
+	
+//	printk("finishing ");
 	end_that_request_last( req );
+//	printk("done\n");
 }
 
 
@@ -238,7 +263,7 @@
 
 static void i2o_block_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg)
 {
-	struct request *req;
+	struct i2ob_request *ireq;
 	u8 st;
 	u32 *m = (u32 *)msg;
 	u8 unit = (m[2]>>8)&0xF0;	/* low 4 bits are partition */
@@ -265,7 +290,7 @@
 		
 		/* We need to up the request failure count here and maybe
 		   abort it */
-		req=(struct request *)m[3];
+		ireq=&i2ob_queue[m[3]];
 		/* Now flush the message by making it a NOP */
 		m[0]&=0x00FFFFFF;
 		m[0]|=(I2O_CMD_UTIL_NOP)<<24;
@@ -288,7 +313,7 @@
 		 *	request in the context.
 		 */
 		 
-		req=(struct request *)m[3];
+		ireq=&i2ob_queue[m[3]];
 		st=m[4]>>24;
 	
 		if(st!=0)
@@ -297,7 +322,7 @@
 			/*
 			 *	Now error out the request block
 			 */
-			req->errors++;	
+			ireq->req->errors++;	
 		}
 	}
 	/*
@@ -306,8 +331,8 @@
 	
 	spin_lock(&io_request_lock);
 	spin_lock(&i2ob_lock);
-	i2ob_unhook_request(&i2ob_dev[unit], req);
-	i2ob_end_request(req);
+	i2ob_unhook_request(ireq);
+	i2ob_end_request(ireq->req);
 	
 	/*
 	 *	We may be able to do more I/O
@@ -329,30 +354,6 @@
 
 
 /*
- *	Flush all pending requests as errors. Must call with the queue
- *	locked.
- */
- 
-#if 0
-static void i2ob_clear_queue(struct i2ob_device *dev)
-{
-	struct request *req;
-
-	while (1) {
-		req = dev->tail;
-		if (!req)
-			return;
-		req->errors++;
-		i2ob_end_request(req);
-
-		if (dev->tail == dev->head)
-			dev->head = NULL;
-		dev->tail = dev->tail->next;
-	}
-}
-#endif
-
-/*
  *	The I2O block driver is listed as one of those that pulls the
  *	front entry off the queue before processing it. This is important
  *	to remember here. If we drop the io lock then CURRENT will change
@@ -363,6 +364,7 @@
 static void do_i2ob_request(void)
 {
 	struct request *req;
+	struct i2ob_request *ireq;
 	int unit;
 	struct i2ob_device *dev;
 	u32 m;
@@ -400,15 +402,13 @@
 		req->errors = 0;
 		CURRENT = CURRENT->next;
 		req->next = NULL;
+		req->sem = NULL;
+		
+		ireq = i2ob_qhead;
+		i2ob_qhead = ireq->next;
+		ireq->req = req;
 
-		if (dev->head == NULL) {
-			dev->head = req;
-			dev->tail = req;
-		} else {
-			dev->tail->next = req;
-			dev->tail = req;
-		}
-		i2ob_send(m, dev, req, i2ob[unit].start_sect, (unit&0xF0));
+		i2ob_send(m, dev, ireq, i2ob[unit].start_sect, (unit&0xF0));
 	}
 }
 
@@ -727,8 +727,6 @@
 	i2ob_hardsizes[unit] = blocksize;
 	i2ob_gendisk.part[unit].nr_sects = i2ob_sizes[unit];
 
-	/* Setting this higher than 1024 breaks the symbios for some reason */
-		
 	limit=4096;	/* 8 deep scatter gather */
 
 	printk("Byte limit is %d.\n", limit);
@@ -962,7 +960,7 @@
 {
 	int i;
 
-	printk(KERN_INFO "I2O block device OSM v0.06. (C) 1999 Red Hat Software.\n");
+	printk(KERN_INFO "I2O block device OSM v0.07. (C) 1999 Red Hat Software.\n");
 	
 	/*
 	 *	Register the block device interfaces
@@ -1000,6 +998,20 @@
 	}
 	
 	/*
+	 *	Set up the queue
+	 */
+	
+	for(i = 0; i< MAX_I2OB_DEPTH; i++)
+	{
+		i2ob_queue[i].next = &i2ob_queue[i+1];
+		i2ob_queue[i].num = i;
+	}
+	
+	/* Queue is MAX_I2OB + 1... */
+	i2ob_queue[i].next = NULL;
+	i2ob_qhead = &i2ob_queue[0];
+	
+	/*
 	 *	Register the OSM handler as we will need this to probe for
 	 *	drives, geometry and other goodies.
 	 */
@@ -1045,8 +1057,6 @@
 	 */
 	if (unregister_blkdev(MAJOR_NR, "i2o_block") != 0)
 		printk("i2o_block: cleanup_module failed\n");
-	else
-		printk("i2o_block: module cleaned up.\n");
 
 	/*
 	 *	Why isnt register/unregister gendisk in the kernel ???
diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_core.c linux/drivers/i2o/i2o_core.c
--- v2.3.16/linux/drivers/i2o/i2o_core.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/i2o/i2o_core.c	Tue Sep  7 10:22:12 1999
@@ -265,7 +265,7 @@
 	spin_lock(&i2o_configuration_lock);
 	if(atomic_read(&c->users))
 	{
-		printk("Someones using controller iop%d\n", c->unit);
+		printk("Someone is using controller iop%d\n", c->unit);
 		spin_unlock(&i2o_configuration_lock);
 		return -EBUSY;
 	}
@@ -1058,7 +1058,7 @@
 
 	/* Wait for a reply */
 	time=jiffies;
-		 
+
 	while(status_block[87]!=0xFF)
 	{
 		if((jiffies-time)>=5*HZ)
diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_pci.c linux/drivers/i2o/i2o_pci.c
--- v2.3.16/linux/drivers/i2o/i2o_pci.c	Fri Aug  6 11:16:54 1999
+++ linux/drivers/i2o/i2o_pci.c	Tue Sep  7 10:22:12 1999
@@ -105,7 +105,7 @@
 		/* Skip I/O spaces */
 		if(!(dev->resource[i].flags&PCI_BASE_ADDRESS_SPACE))
 		{
-			memptr=dev->resource[i].flags;
+			memptr=dev->resource[i].start;
 			break;
 		}
 	}
@@ -113,14 +113,21 @@
 	if(i==6)
 	{
 		printk(KERN_ERR "i2o_pci: I2O controller has no memory regions defined.\n");
-		return -ENOMEM;
+		kfree(c);
+		return -EINVAL;
 	}
 	
 	size = dev->resource[i].end-dev->resource[i].start+1;	
 	/* Map the I2O controller */
 	
-	printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, -size);
-	mem = ioremap(memptr, -size);
+	printk(KERN_INFO "PCI I2O controller at 0x%08X size=%d\n", memptr, size);
+	mem = ioremap(memptr, size);
+	if(mem==NULL)
+	{
+		printk(KERN_ERR "i2o_pci: Unable to map controller.\n");
+		kfree(c);
+		return -EINVAL;
+	}
 	
 	c->bus.pci.irq = -1;
 
@@ -148,6 +155,8 @@
 	if(i<0)
 	{
 		printk(KERN_ERR "i2o: unable to install controller.\n");
+		kfree(c);
+		iounmap(mem);
 		return i;
 	}
 
@@ -165,7 +174,9 @@
 			core->delete(c);
 #else
 			i2o_delete_controller(c);
-#endif /* MODULE */
+#endif /* MODULE */	
+			kfree(c);
+			iounmap(mem);
 			return -EBUSY;
 		}
 	}
@@ -190,8 +201,7 @@
 		}
 		printk(KERN_INFO "I2O controller on bus %d at %d.\n",
 			dev->bus->number, dev->devfn);
-		if(!dev->master)
-			printk(KERN_WARNING "Controller not master enabled.\n");
+		pci_set_master(dev);
 		if(i2o_pci_install(dev)==0)
 			count++;
 	}
@@ -247,6 +257,7 @@
 
 		if(c==NULL)
 			continue;		
+			
 		if(c->type == I2O_TYPE_PCI)
 		{
 #ifdef MODULE
@@ -265,7 +276,6 @@
 #endif
 				continue;
 			}
-		
 			I2O_IRQ_WRITE32(c,0);
 		}
 #ifdef MODULE
diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_scsi.c linux/drivers/i2o/i2o_scsi.c
--- v2.3.16/linux/drivers/i2o/i2o_scsi.c	Thu Aug  5 15:04:52 1999
+++ linux/drivers/i2o/i2o_scsi.c	Thu Sep  2 10:02:32 1999
@@ -317,7 +317,7 @@
 	return 0;
 }
 
-static void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
+void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt)
 {
 	struct i2o_device *unit;
 	struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata;
diff -u --recursive --new-file v2.3.16/linux/drivers/i2o/i2o_scsi.h linux/drivers/i2o/i2o_scsi.h
--- v2.3.16/linux/drivers/i2o/i2o_scsi.h	Wed Jun  2 14:40:22 1999
+++ linux/drivers/i2o/i2o_scsi.h	Tue Sep  7 10:22:12 1999
@@ -11,7 +11,7 @@
 #include <linux/kdev_t.h>
 
 #define I2O_SCSI_ID 15
-#define I2O_SCSI_CAN_QUEUE 8
+#define I2O_SCSI_CAN_QUEUE 4
 #define I2O_SCSI_CMD_PER_LUN 6
 
 extern struct proc_dir_entry proc_scsi_i2o_scsi;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/eicon/eicon_mod.c linux/drivers/isdn/eicon/eicon_mod.c
--- v2.3.16/linux/drivers/isdn/eicon/eicon_mod.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/isdn/eicon/eicon_mod.c	Wed Sep  1 15:35:22 1999
@@ -1275,8 +1275,8 @@
 #define eicon_init init_module
 #endif
 
-__initfunc(int
-eicon_init(void))
+int __init
+eicon_init(void)
 {
 	int card_count = 0;
 	int release = 0;
@@ -1392,8 +1392,8 @@
 
 	str = get_options(line, 4, ints);
 #else
-__initfunc(void
-eicon_setup(char *str, int *ints))
+void __init
+eicon_setup(char *str, int *ints)
 {
         int i, argc;
 #endif
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/amd7930.c linux/drivers/isdn/hisax/amd7930.c
--- v2.3.16/linux/drivers/isdn/hisax/amd7930.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/amd7930.c	Sat Sep  4 13:12:51 1999
@@ -749,8 +749,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init
+setup_amd7930(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c
--- v2.3.16/linux/drivers/isdn/hisax/asuscom.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/asuscom.c	Sat Sep  4 13:12:51 1999
@@ -326,8 +326,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init
+setup_asuscom(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/avm_a1.c linux/drivers/isdn/hisax/avm_a1.c
--- v2.3.16/linux/drivers/isdn/hisax/avm_a1.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/avm_a1.c	Sat Sep  4 13:12:51 1999
@@ -227,8 +227,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_avm_a1(struct IsdnCard *card))
+int __init
+setup_avm_a1(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/avm_a1p.c linux/drivers/isdn/hisax/avm_a1p.c
--- v2.3.16/linux/drivers/isdn/hisax/avm_a1p.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/avm_a1p.c	Sat Sep  4 13:12:51 1999
@@ -262,8 +262,8 @@
 	return 0;
 }
 
-__initfunc(int
-setup_avm_a1_pcmcia(struct IsdnCard *card))
+int __init
+setup_avm_a1_pcmcia(struct IsdnCard *card)
 {
 	u_char model, vers;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/avm_pci.c linux/drivers/isdn/hisax/avm_pci.c
--- v2.3.16/linux/drivers/isdn/hisax/avm_pci.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/avm_pci.c	Sat Sep  4 13:12:51 1999
@@ -779,8 +779,8 @@
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_avm_pcipnp(struct IsdnCard *card))
+int __init
+setup_avm_pcipnp(struct IsdnCard *card)
 {
 	u_int val, ver;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/bkm_a4t.c linux/drivers/isdn/hisax/bkm_a4t.c
--- v2.3.16/linux/drivers/isdn/hisax/bkm_a4t.c	Thu Aug 26 13:05:35 1999
+++ linux/drivers/isdn/hisax/bkm_a4t.c	Sat Sep  4 13:12:51 1999
@@ -294,8 +294,8 @@
 static int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-	   setup_bkm_a4t(struct IsdnCard *card))
+int __init
+	   setup_bkm_a4t(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/bkm_a8.c linux/drivers/isdn/hisax/bkm_a8.c
--- v2.3.16/linux/drivers/isdn/hisax/bkm_a8.c	Thu Aug 26 13:05:35 1999
+++ linux/drivers/isdn/hisax/bkm_a8.c	Sat Sep  4 13:12:51 1999
@@ -347,8 +347,8 @@
 static int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-	   setup_sct_quadro(struct IsdnCard *card))
+int __init
+	   setup_sct_quadro(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/config.c linux/drivers/isdn/hisax/config.c
--- v2.3.16/linux/drivers/isdn/hisax/config.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/isdn/hisax/config.c	Sat Sep  4 13:12:51 1999
@@ -571,8 +571,8 @@
 
 	str = get_options(line, MAX_ARG, ints);
 #else
-__initfunc(void
-HiSax_setup(char *str, int *ints))
+void __init
+HiSax_setup(char *str, int *ints)
 {
 	int i, j, argc;
 #endif        
@@ -1442,8 +1442,8 @@
 }
 
 
-__initfunc(int
-HiSax_init(void))
+int __init
+HiSax_init(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c
--- v2.3.16/linux/drivers/isdn/hisax/diva.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/diva.c	Sat Sep  4 13:12:51 1999
@@ -888,8 +888,8 @@
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_diva(struct IsdnCard *card))
+int __init
+setup_diva(struct IsdnCard *card)
 {
 	int bytecnt;
 	u_char val;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/gazel.c linux/drivers/isdn/hisax/gazel.c
--- v2.3.16/linux/drivers/isdn/hisax/gazel.c	Thu Aug 26 13:05:35 1999
+++ linux/drivers/isdn/hisax/gazel.c	Sat Sep  4 13:12:51 1999
@@ -690,8 +690,8 @@
 	return (0);
 }
 
-__initfunc(int
-	   setup_gazel(struct IsdnCard *card))
+int __init
+	   setup_gazel(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfc_2bds0.c linux/drivers/isdn/hisax/hfc_2bds0.c
--- v2.3.16/linux/drivers/isdn/hisax/hfc_2bds0.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/hfc_2bds0.c	Sat Sep  4 13:12:51 1999
@@ -1172,8 +1172,8 @@
 #endif
 }
 
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int * __init
+init_send_hfcd(int cnt)
 {
 	int i, *send;
 
@@ -1187,8 +1187,8 @@
 	return(send);
 }
 
-__initfunc(void
-init2bds0(struct IsdnCardState *cs))
+void __init
+init2bds0(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcd;
 	cs->dbusytimer.function = (void *) hfc_dbusy_timer;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfc_2bs0.c linux/drivers/isdn/hisax/hfc_2bs0.c
--- v2.3.16/linux/drivers/isdn/hisax/hfc_2bs0.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/hfc_2bs0.c	Sat Sep  4 13:12:51 1999
@@ -559,8 +559,8 @@
 	return (0);
 }
 
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init
+init_send(struct BCState *bcs)
 {
 	int i;
 
@@ -573,8 +573,8 @@
 		bcs->hw.hfc.send[i] = 0x1fff;
 }
 
-__initfunc(void
-inithfc(struct IsdnCardState *cs))
+void __init
+inithfc(struct IsdnCardState *cs)
 {
 	init_send(&cs->bcs[0]);
 	init_send(&cs->bcs[1]);
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfc_pci.c linux/drivers/isdn/hisax/hfc_pci.c
--- v2.3.16/linux/drivers/isdn/hisax/hfc_pci.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/isdn/hisax/hfc_pci.c	Sat Sep  4 13:12:51 1999
@@ -1513,8 +1513,8 @@
 /*************************************/
 /* Alloc memory send data for queues */
 /*************************************/
-__initfunc(unsigned int
-	   *init_send_hfcpci(int cnt))
+unsigned int * __init 
+	init_send_hfcpci(int cnt)
 {
 	int i, *send;
 
@@ -1531,8 +1531,8 @@
 /********************************/
 /* called for card init message */
 /********************************/
-__initfunc(void
-	   inithfcpci(struct IsdnCardState *cs))
+void __init
+	inithfcpci(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcpci;
 	cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
@@ -1604,8 +1604,8 @@
 
 #endif				/* CONFIG_PCI */
 
-__initfunc(int
-	   setup_hfcpci(struct IsdnCard *card))
+int __init
+	setup_hfcpci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hfcscard.c linux/drivers/isdn/hisax/hfcscard.c
--- v2.3.16/linux/drivers/isdn/hisax/hfcscard.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/hfcscard.c	Sat Sep  4 13:12:51 1999
@@ -148,8 +148,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_hfcs(struct IsdnCard *card))
+int __init
+setup_hfcs(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/hisax.h linux/drivers/isdn/hisax/hisax.h
--- v2.3.16/linux/drivers/isdn/hisax/hisax.h	Thu Aug 26 13:05:35 1999
+++ linux/drivers/isdn/hisax/hisax.h	Wed Sep  1 15:35:22 1999
@@ -1007,6 +1007,10 @@
 #define __initdata
 #endif
 
+#ifndef __init
+#define __init
+#endif
+
 #define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
 #define HISAX_INITDATA __initdata
 
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/isurf.c linux/drivers/isdn/hisax/isurf.c
--- v2.3.16/linux/drivers/isdn/hisax/isurf.c	Thu Aug 26 13:05:36 1999
+++ linux/drivers/isdn/hisax/isurf.c	Sat Sep  4 13:12:51 1999
@@ -206,8 +206,8 @@
 	return(isar_auxcmd(cs, ic));
 }
 
-__initfunc(int
-setup_isurf(struct IsdnCard *card))
+int __init
+setup_isurf(struct IsdnCard *card)
 {
 	int ver;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/ix1_micro.c linux/drivers/isdn/hisax/ix1_micro.c
--- v2.3.16/linux/drivers/isdn/hisax/ix1_micro.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/ix1_micro.c	Sat Sep  4 13:12:51 1999
@@ -282,8 +282,8 @@
 }
 
 
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init
+setup_ix1micro(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/mic.c linux/drivers/isdn/hisax/mic.c
--- v2.3.16/linux/drivers/isdn/hisax/mic.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/mic.c	Sat Sep  4 13:12:51 1999
@@ -224,8 +224,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init
+setup_mic(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c
--- v2.3.16/linux/drivers/isdn/hisax/netjet.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/netjet.c	Sat Sep  4 13:12:51 1999
@@ -889,8 +889,8 @@
 }
 
  
-__initfunc(void
-inittiger(struct IsdnCardState *cs))
+void __init
+inittiger(struct IsdnCardState *cs)
 {
 	if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
 		GFP_KERNEL | GFP_DMA))) {
@@ -1080,8 +1080,8 @@
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_netjet(struct IsdnCard *card))
+int __init
+setup_netjet(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/niccy.c linux/drivers/isdn/hisax/niccy.c
--- v2.3.16/linux/drivers/isdn/hisax/niccy.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/niccy.c	Sat Sep  4 13:12:51 1999
@@ -265,8 +265,8 @@
 static  int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_niccy(struct IsdnCard *card))
+int __init
+setup_niccy(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/s0box.c linux/drivers/isdn/hisax/s0box.c
--- v2.3.16/linux/drivers/isdn/hisax/s0box.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/s0box.c	Sat Sep  4 13:12:51 1999
@@ -212,8 +212,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/saphir.c linux/drivers/isdn/hisax/saphir.c
--- v2.3.16/linux/drivers/isdn/hisax/saphir.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/saphir.c	Sat Sep  4 13:12:51 1999
@@ -265,8 +265,8 @@
 }
 
 
-__initfunc(int
-setup_saphir(struct IsdnCard *card))
+int __init
+setup_saphir(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c
--- v2.3.16/linux/drivers/isdn/hisax/sedlbauer.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/isdn/hisax/sedlbauer.c	Sat Sep  4 13:12:51 1999
@@ -549,8 +549,8 @@
 #endif
 #endif
 
-__initfunc(int
-setup_sedlbauer(struct IsdnCard *card))
+int __init
+setup_sedlbauer(struct IsdnCard *card)
 {
 	int bytecnt, ver, val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c
--- v2.3.16/linux/drivers/isdn/hisax/sportster.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/sportster.c	Sat Sep  4 13:12:51 1999
@@ -208,8 +208,8 @@
 	return(0);
 }
 
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+int __init
+get_io_range(struct IsdnCardState *cs)
 {
 	int i, j, adr;
 	
@@ -234,8 +234,8 @@
 	}
 }
 
-__initfunc(int
-setup_sportster(struct IsdnCard *card))
+int __init
+setup_sportster(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c
--- v2.3.16/linux/drivers/isdn/hisax/teleint.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/teleint.c	Sat Sep  4 13:12:51 1999
@@ -289,8 +289,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init
+setup_TeleInt(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/teles0.c linux/drivers/isdn/hisax/teles0.c
--- v2.3.16/linux/drivers/isdn/hisax/teles0.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/teles0.c	Sat Sep  4 13:12:51 1999
@@ -295,8 +295,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init
+setup_teles0(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/teles3.c linux/drivers/isdn/hisax/teles3.c
--- v2.3.16/linux/drivers/isdn/hisax/teles3.c	Tue Aug 31 17:29:13 1999
+++ linux/drivers/isdn/hisax/teles3.c	Sat Sep  4 13:12:51 1999
@@ -321,8 +321,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int __init
+setup_teles3(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --recursive --new-file v2.3.16/linux/drivers/isdn/hisax/telespci.c linux/drivers/isdn/hisax/telespci.c
--- v2.3.16/linux/drivers/isdn/hisax/telespci.c	Thu Aug 12 09:42:33 1999
+++ linux/drivers/isdn/hisax/telespci.c	Sat Sep  4 13:12:51 1999
@@ -310,8 +310,8 @@
 static 	int pci_index __initdata = 0;
 #endif
 
-__initfunc(int
-setup_telespci(struct IsdnCard *card))
+int __init
+setup_telespci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --recursive --new-file v2.3.16/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.3.16/linux/drivers/net/Config.in	Thu Aug 26 13:05:37 1999
+++ linux/drivers/net/Config.in	Sat Sep  4 13:11:36 1999
@@ -95,6 +95,10 @@
       tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
       tristate 'SiS 900 PCI Fast Ethernet Adapter support' CONFIG_SIS900
       tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
+      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
+      if [ "$CONFIG_ACENIC" != "n" ]; then
+	  bool 'Omit support for old Tigon I based AceNICs' CONFIG_ACENIC_OMIT_TIGON_I
+      fi
   fi
   bool 'Other ISA cards' CONFIG_NET_ISA
   if [ "$CONFIG_NET_ISA" = "y" ]; then
@@ -125,7 +129,6 @@
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support' CONFIG_ACENIC
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
 
diff -u --recursive --new-file v2.3.16/linux/drivers/net/Makefile linux/drivers/net/Makefile
--- v2.3.16/linux/drivers/net/Makefile	Thu Aug 26 13:05:37 1999
+++ linux/drivers/net/Makefile	Sat Sep  4 13:08:32 1999
@@ -412,6 +412,10 @@
   endif
 endif
 
+ifeq ($(CONFIG_SUN3LANCE),y)
+L_OBJS += sun3lance.o
+endif
+
 ifeq ($(CONFIG_PCNET32),y)
 L_OBJS += pcnet32.o
 else
diff -u --recursive --new-file v2.3.16/linux/drivers/net/Space.c linux/drivers/net/Space.c
--- v2.3.16/linux/drivers/net/Space.c	Thu Aug 26 13:05:37 1999
+++ linux/drivers/net/Space.c	Sat Sep  4 13:08:32 1999
@@ -93,6 +93,7 @@
 extern int myri_sbus_probe(struct net_device *);
 extern int sgiseeq_probe(struct net_device *);
 extern int atarilance_probe(struct net_device *);
+extern int sun3lance_probe(struct net_device *);
 extern int a2065_probe(struct net_device *);
 extern int ariadne_probe(struct net_device *);
 extern int ariadne2_probe(struct net_device *);
@@ -409,6 +410,9 @@
 struct devprobe m68k_probes[] __initdata = {
 #ifdef CONFIG_ATARILANCE	/* Lance-based Atari ethernet boards */
 	{atarilance_probe, 0},
+#endif
+#ifdef CONFIG_SUN3LANCE         /* sun3 onboard Lance chip */
+	{sun3lance_probe, 0},
 #endif
 #ifdef CONFIG_A2065		/* Commodore/Ameristar A2065 Ethernet Board */
 	{a2065_probe, 0},
diff -u --recursive --new-file v2.3.16/linux/drivers/net/acenic.c linux/drivers/net/acenic.c
--- v2.3.16/linux/drivers/net/acenic.c	Thu Aug 26 13:05:37 1999
+++ linux/drivers/net/acenic.c	Sat Sep  4 13:11:36 1999
@@ -18,13 +18,12 @@
  * (at your option) any later version.
  *
  * Additional work by Pete Wyckoff <wyckoff@ca.sandia.gov> for initial
- * Alpha and trace dump support.
+ * Alpha and trace dump support. The trace dump support has not been
+ * integrated yet however.
  */
 
-#define PKT_COPY_THRESHOLD 300
-
+#include <linux/config.h>
 #include <linux/module.h>
-
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
@@ -36,6 +35,9 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#ifdef ETHTOOL
+#include <linux/ethtool.h>
+#endif
 #include <net/sock.h>
 #include <net/ip.h>
 
@@ -45,16 +47,12 @@
 #include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
-#include "acenic.h"
-
-/*
- * These must be defined before the firmware is included.
- */
-#define MAX_TEXT_LEN	96*1024
-#define MAX_RODATA_LEN	8*1024
-#define MAX_DATA_LEN	2*1024
 
-#include "acenic_firmware.h"
+#ifdef CONFIG_ACENIC_OMIT_TIGON_I
+#define ACE_IS_TIGON_I(ap)	0
+#else
+#define ACE_IS_TIGON_I(ap)	(ap->version == 1)
+#endif
 
 #ifndef PCI_VENDOR_ID_ALTEON
 #define PCI_VENDOR_ID_ALTEON		0x12ae	
@@ -73,10 +71,32 @@
 #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
 #define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a
 #endif
-#ifndef PCI_VENDOR_ID_SGI_ACENIC
+#ifndef PCI_VENDOR_ID_SGI
+#define PCI_VENDOR_ID_SGI             0x10a9
+#endif
+#ifndef PCI_DEVICE_ID_SGI_ACENIC
 #define PCI_DEVICE_ID_SGI_ACENIC      0x0009
 #endif
 
+#ifndef wmb
+#define wmb()	mb()
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02030e)
+#define net_device device
+#endif
+
+#include "acenic.h"
+
+/*
+ * These must be defined before the firmware is included.
+ */
+#define MAX_TEXT_LEN	96*1024
+#define MAX_RODATA_LEN	8*1024
+#define MAX_DATA_LEN	2*1024
+
+#include "acenic_firmware.h"
+
 /*
  * This driver currently supports Tigon I and Tigon II based cards
  * including the Alteon AceNIC and the 3Com 3C985. The driver should
@@ -146,6 +166,12 @@
  *                is available, on the 1/2MB NIC app. 300KB is available.
  *                68KB will always be available as a minimum for both
  *                directions. The default value is a 50/50 split.
+ *  dis_pci_mem_inval=<val> - disable PCI memory write and invalidate
+ *                operations, default (1) is to always disable this as
+ *                that is what Alteon does on NT. I have not been able
+ *                to measure any real performance differences with
+ *                this on my systems. Set <val>=0 if you want to
+ *                enable these operations.
  *
  * If you use more than one NIC, specify the parameters for the
  * individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to
@@ -159,18 +185,98 @@
  *
  * The mini ring is not used under Linux and I am not sure it makes sense
  * to actually use it.
+ *
+ * New interrupt handler strategy:
+ *
+ * The old interrupt handler worked using the traditional method of
+ * replacing an skbuff with a new one when a packet arrives. However
+ * the rx rings do not need to contain a static number of buffer
+ * descriptors, thus it makes sense to move the memory allocation out
+ * of the main interrupt handler and do it in a bottom half handler
+ * and only allocate new buffers when the number of buffers in the
+ * ring is below a certain threshold. In order to avoid starving the
+ * NIC under heavy load it is however necessary to force allocation
+ * when hitting a minimum threshold. The strategy for alloction is as
+ * follows:
+ *
+ *     RX_LOW_BUF_THRES    - allocate buffers in the bottom half
+ *     RX_PANIC_LOW_THRES  - we are very low on buffers, allocate
+ *                           the buffers in the interrupt handler
+ *     RX_RING_THRES       - maximum number of buffers in the rx ring
+ *     RX_MINI_THRES       - maximum number of buffers in the mini ring
+ *     RX_JUMBO_THRES      - maximum number of buffers in the jumbo ring
+ *
+ * One advantagous side effect of this allocation approach is that the
+ * entire rx processing can be done without holding any spin lock
+ * since the rx rings and registers are totally independant of the tx
+ * ring and its registers.  This of course includes the kmalloc's of
+ * new skb's. Thus start_xmit can run in parallel with rx processing
+ * and the memory allocation on SMP systems.
+ *
+ * Note that running the skb reallocation in a bottom half opens up
+ * another can of races which needs to be handled properly. In
+ * particular it can happen that the interrupt handler tries to run
+ * the reallocation while the bottom half is either running on another
+ * CPU or was interrupted on the same CPU. To get around this the
+ * driver uses bitops to prevent the reallocation routines from being
+ * reentered.
+ *
+ * TX handling can also be done without holding any spin lock, wheee
+ * this is fun! since tx_ret_csm is only written to by the interrupt
+ * handler. The case to be aware of is when shutting down the device
+ * and cleaning up where it is necessary to make sure that
+ * start_xmit() is not running while this is happening. Well DaveM
+ * informs me that this case is already protected against ... bye bye
+ * Mr. Spin Lock, it was nice to know you.
+ *
+ * TX interrupts are now partly disabled so the NIC will only generate
+ * TX interrupts for the number of coal ticks, not for the number of
+ * TX packets in the queue. This should reduce the number of TX only,
+ * ie. when no RX processing is done, interrupts seen.
  */
 
 /*
- * Default values for tuning parameters
+ * Threshold values for RX buffer allocation - the low water marks for
+ * when to start refilling the rings are set to 75% of the ring
+ * sizes. It seems to make sense to refill the rings entirely from the
+ * intrrupt handler once it gets below the panic threshold, that way
+ * we don't risk that the refilling is moved to another CPU when the
+ * one running the interrupt handler just got the slab code hot in its
+ * cache.
  */
-#define DEF_TX_RATIO	31
-#define DEF_TX_COAL	1000
-#define DEF_TX_MAX_DESC	40
-#define DEF_RX_COAL	1000
-#define DEF_RX_MAX_DESC	20
-#define DEF_TRACE	0
-#define DEF_STAT	2 * TICKS_PER_SEC
+#define RX_RING_SIZE		72
+#define RX_MINI_SIZE		64
+#define RX_JUMBO_SIZE		48
+
+#define RX_PANIC_STD_THRES	16
+#define RX_PANIC_STD_REFILL	(3*RX_PANIC_STD_THRES)/2
+#define RX_LOW_STD_THRES	(3*RX_RING_SIZE)/4
+#define RX_PANIC_MINI_THRES	12
+#define RX_PANIC_MINI_REFILL	(3*RX_PANIC_MINI_THRES)/2
+#define RX_LOW_MINI_THRES	(3*RX_MINI_SIZE)/4
+#define RX_PANIC_JUMBO_THRES	6
+#define RX_PANIC_JUMBO_REFILL	(3*RX_PANIC_JUMBO_THRES)/2
+#define RX_LOW_JUMBO_THRES	(3*RX_JUMBO_SIZE)/4
+
+
+/*
+ * Size of the mini ring entries, basically these just should be big
+ * enough to take TCP ACKs
+ */
+#define ACE_MINI_SIZE		100
+
+#define ACE_MINI_BUFSIZE	(ACE_MINI_SIZE + 2 + 16)
+#define ACE_STD_BUFSIZE		(ACE_STD_MTU + ETH_HLEN + 2+4+16)
+#define ACE_JUMBO_BUFSIZE	(ACE_JUMBO_MTU + ETH_HLEN + 2+4+16)
+
+#define DEF_TX_RATIO		24
+#define DEF_TX_COAL		1000
+#define DEF_TX_MAX_DESC		40
+#define DEF_RX_COAL		1000
+#define DEF_RX_MAX_DESC		20
+#define TX_COAL_INTS_ONLY	0	/* seems not worth it */
+#define DEF_TRACE		0
+#define DEF_STAT		2 * TICKS_PER_SEC
 
 static int link[8] = {0, };
 static int trace[8] = {0, };
@@ -179,25 +285,20 @@
 static int max_tx_desc[8] = {0, };
 static int max_rx_desc[8] = {0, };
 static int tx_ratio[8] = {0, };
+static int dis_pci_mem_inval[8] = {1, 1, 1, 1, 1, 1, 1, 1};
 
-static const char __initdata *version = "acenic.c: v0.33a 08/16/99  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
+static const char __initdata *version = "acenic.c: v0.34 09/03/99  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
 
 static struct net_device *root_dev = NULL;
 
 static int probed __initdata = 0;
 
+
 int __init acenic_probe (struct net_device *dev)
 {
 	int boards_found = 0;
 	int version_disp;
 	struct ace_private *ap;
-	u8 pci_latency;
-#if 0
-	u16 vendor, device;
-	u8 pci_bus;
-	u8 pci_dev_fun;
-	u8 irq;
-#endif
 	struct pci_dev *pdev = NULL;
 
 	if (probed)
@@ -243,29 +344,18 @@
 
 		ap = dev->priv;
 		ap->pdev = pdev;
-		ap->vendor = pdev->vendor;
 
 		dev->irq = pdev->irq;
-#ifdef __SMP__
-		spin_lock_init(&ap->lock);
-#endif
 
 		dev->open = &ace_open;
 		dev->hard_start_xmit = &ace_start_xmit;
 		dev->stop = &ace_close;
 		dev->get_stats = &ace_get_stats;
 		dev->set_multicast_list = &ace_set_multicast_list;
-#if 0
 		dev->do_ioctl = &ace_ioctl;
-#endif
 		dev->set_mac_address = &ace_set_mac_addr;
 		dev->change_mtu = &ace_change_mtu;
 
-		/*
-		 * Dummy value.
-		 */
-		dev->base_addr = 42;
-
 		/* display version info if adapter is found */
 		if (!version_disp)
 		{
@@ -277,16 +367,36 @@
 
 		pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
 
-		pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
-		if (pci_latency <= 0x40){
-			pci_latency = 0x40;
+		pci_read_config_byte(pdev, PCI_LATENCY_TIMER,
+				     &ap->pci_latency);
+		if (ap->pci_latency <= 0x40){
+			ap->pci_latency = 0x40;
 			pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
-					      pci_latency);
+					      ap->pci_latency);
 		}
 
 		pci_set_master(pdev);
 
-		switch(ap->vendor){
+		/*
+		 * Remap the regs into kernel space - this is abuse of
+		 * dev->base_addr since it was means for I/O port
+		 * addresses but who gives a damn.
+		 */
+#if (LINUX_VERSION_CODE < 0x02030d)
+		dev->base_addr = pdev->base_address[0];
+#else
+		dev->base_addr = pdev->resource[0].start;
+#endif
+
+		ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
+		if (!ap->regs){
+			printk(KERN_ERR "%s:  Unable to map I/O register, "
+			       "AceNIC %i will be disabled.\n",
+			       dev->name, boards_found);
+			break;
+		}
+
+		switch(pdev->vendor){
 		case PCI_VENDOR_ID_ALTEON:
 			sprintf(ap->name, "AceNIC Gigabit Ethernet");
 			printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
@@ -316,21 +426,18 @@
 			printk(KERN_INFO "%s: Unknown AceNIC ", dev->name);
 			break;
 		}
-		printk("Gigabit Ethernet at 0x%08lx, irq %i, PCI latency %i "
-		       "clks\n", pdev->resource[0].start, dev->irq, pci_latency);
+		printk("Gigabit Ethernet at 0x%08lx, irq %i\n",
+		       dev->base_addr, dev->irq);
 
-		/*
-		 * Remap the regs into kernel space.
-		 */
-
-		ap->regs = (struct ace_regs *)ioremap(pdev->resource[0].start,
-						      0x4000);
-		if (!ap->regs){
-			printk(KERN_ERR "%s:  Unable to map I/O register, "
-			       "AceNIC %i will be disabled.\n",
-			       dev->name, boards_found);
-			break;
+#ifdef CONFIG_ACENIC_OMIT_TIGON_I
+		if ((readl(&ap->regs->HostCtrl) >> 28) == 4) {
+			printk(KERN_ERR "%s: Driver compiled without Tigon I"
+			       " support - NIC disabled\n", dev->name);
+			iounmap(ap->regs);
+			unregister_netdev(dev);
+			continue;
 		}
+#endif
 
 #ifdef MODULE
 		if (ace_init(dev, boards_found))
@@ -341,12 +448,6 @@
 #endif
 
 		boards_found++;
-
-		/*
-		 * This is bollocks, but we need to tell the net-init
-		 * code that it shall go for the next device.
-		 */
-		dev->base_addr = 0;
 	}
 
 	/*
@@ -378,6 +479,7 @@
 MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
 #endif
 
+
 int init_module(void)
 {
 	int cards;
@@ -388,37 +490,54 @@
 	return cards ? 0 : -ENODEV;
 }
 
+
 void cleanup_module(void)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
 	struct net_device *next;
 	short i;
-	unsigned long flags;
 
 	while (root_dev){
 		next = ((struct ace_private *)root_dev->priv)->next;
 		ap = (struct ace_private *)root_dev->priv;
 
 		regs = ap->regs;
-		spin_lock_irqsave(&ap->lock, flags);
 
 		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
-		if (ap->version == 2)
+		if (ap->version >= 2)
 			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
 			       &regs->CpuBCtrl);
+		/*
+		 * This clears any pending interrupts
+		 */
 		writel(0, &regs->Mb0Lo);
 
-		spin_unlock_irqrestore(&ap->lock, flags);
-
 		/*
-		 * Release the RX buffers.
+		 * Make sure no other CPUs are processing interrupts
+		 * on the card before the buffers are being released.
+		 * Otherwise one might experience some `interesting'
+		 * effects.
+		 *
+		 * Then release the RX buffers - jumbo buffers were
+		 * already released in ace_close().
 		 */
+		synchronize_irq();
+
 		for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
-			if (ap->rx_std_skbuff[i]) {
+			if (ap->skb->rx_std_skbuff[i]) {
 				ap->rx_std_ring[i].size = 0;
 				set_aceaddr_bus(&ap->rx_std_ring[i].addr, 0);
-				dev_kfree_skb(ap->rx_std_skbuff[i]);
+				dev_kfree_skb(ap->skb->rx_std_skbuff[i]);
+			}
+		}
+		if (ap->version >= 2) {
+			for (i = 0; i < RX_MINI_RING_ENTRIES; i++) {
+				if (ap->skb->rx_mini_skbuff[i]) {
+					ap->rx_mini_ring[i].size = 0;
+					set_aceaddr_bus(&ap->rx_mini_ring[i].addr, 0);
+					dev_kfree_skb(ap->skb->rx_mini_skbuff[i]);
+				}
 			}
 		}
 
@@ -426,6 +545,7 @@
 		if(ap->trace_buf)
 			kfree(ap->trace_buf);
 		kfree(ap->info);
+		kfree(ap->skb);
 		free_irq(root_dev->irq, root_dev);
 		unregister_netdev(root_dev);
 		kfree(root_dev);
@@ -452,13 +572,13 @@
 }
 
 
-static int __init ace_init(struct net_device *dev, int board_idx)
+static __init int ace_init(struct net_device *dev, int board_idx)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
 	struct ace_info *info;
-	u32 tig_ver, mac1, mac2, tmp;
 	unsigned long tmp_ptr, myjif;
+	u32 tig_ver, mac1, mac2, tmp, pci_state;
 	short i;
 
 	ap = dev->priv;
@@ -486,6 +606,7 @@
 	tig_ver = readl(&regs->HostCtrl) >> 28;
 
 	switch(tig_ver){
+#ifndef CONFIG_ACENIC_OMIT_TIGON_I
 	case 4:
 		printk(KERN_INFO"  Tigon I (Rev. 4), Firmware: %i.%i.%i, ",
 		       tigonFwReleaseMajor, tigonFwReleaseMinor,
@@ -493,6 +614,7 @@
 		writel(0, &regs->LocalCtrl);
 		ap->version = 1;
 		break;
+#endif
 	case 6:
 		printk(KERN_INFO"  Tigon II (Rev. %i), Firmware: %i.%i.%i, ",
 		       tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
@@ -547,24 +669,38 @@
 	dev->dev_addr[4] = (mac2 >> 8) & 0xff;
 	dev->dev_addr[5] = mac2 & 0xff;
 
+	pci_state = readl(&regs->PciState);
+	printk(KERN_INFO "  PCI bus speed: %iMHz, latency: %i clks\n",
+	       (pci_state & PCI_66MHZ) ? 66 : 33, ap->pci_latency);
+
 	/*
 	 * Set the max DMA transfer size. Seems that for most systems
 	 * the performance is better when no MAX parameter is
 	 * set. However for systems enabling PCI write and invalidate,
 	 * DMA writes must be set to the L1 cache line size to get
 	 * optimal performance.
+	 *
+	 * The default is now to turn the PCI write and invalidate off
+	 * - that is what Alteon does for NT.
 	 */
 	tmp = READ_CMD_MEM | WRITE_CMD_MEM;
-	if (ap->version == 2){
-#if 0
+	if (ap->version >= 2){
+		tmp |= (MEM_READ_MULTIPLE | (pci_state & PCI_66MHZ));
 		/*
-		 * According to the documentation this enables writes
-		 * to all PCI regs - NOT good.
+		 * Tuning parameters only supported for 8 cards
 		 */
-		tmp |= DMA_WRITE_ALL_ALIGN;
-#endif
-		tmp |= MEM_READ_MULTIPLE;
-		if (ap->pci_command & PCI_COMMAND_INVALIDATE){
+		if (board_idx > 7 || dis_pci_mem_inval[board_idx]) {
+			if (ap->pci_command & PCI_COMMAND_INVALIDATE) {
+				ap->pci_command &= ~PCI_COMMAND_INVALIDATE;
+				pci_write_config_word(ap->pdev, PCI_COMMAND,
+						      ap->pci_command);
+				printk(KERN_INFO "%s: disabling PCI memory "
+				       "write and invalidate\n", dev->name);
+			}
+		} else if (ap->pci_command & PCI_COMMAND_INVALIDATE){
+			printk(KERN_INFO "%s: PCI memory write & invalidate "
+			       "enabled by BIOS, enabling counter "
+			       "measures\n", dev->name);
 			switch(L1_CACHE_BYTES){
 			case 16:
 				tmp |= DMA_WRITE_MAX_16;
@@ -587,19 +723,23 @@
 	}
 	writel(tmp, &regs->PciState);
 
-	if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) {
-		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
-		       dev->name, dev->irq);
-		return -EAGAIN;
-	}
-
 	/*
 	 * Initialize the generic info block and the command+event rings
 	 * and the control blocks for the transmit and receive rings
 	 * as they need to be setup once and for all.
 	 */
-	if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL))){
-		free_irq(dev->irq, dev);
+	if (!(info = kmalloc(sizeof(struct ace_info), GFP_KERNEL)))
+		return -EAGAIN;
+
+	/*
+	 * Get the memory for the skb rings.
+	 */
+	if (!(ap->skb = kmalloc(sizeof(struct ace_skb), GFP_KERNEL)))
+		return -EAGAIN;
+
+	if (request_irq(dev->irq, ace_interrupt, SA_SHIRQ, ap->name, dev)) {
+		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
+		       dev->name, dev->irq);
 		return -EAGAIN;
 	}
 
@@ -612,6 +752,7 @@
 
 	ap->info = info;
 	memset(info, 0, sizeof(struct ace_info));
+	memset(ap->skb, 0, sizeof(struct ace_skb));
 
 	ace_load_firmware(dev);
 	ap->fw_running = 0;
@@ -631,10 +772,11 @@
 
 	set_aceaddr(&info->evt_prd_ptr, &ap->evt_prd);
 	ap->evt_prd = 0;
+	wmb();
 	writel(0, &regs->EvtCsm);
 
-	info->cmd_ctrl.flags = 0;
 	set_aceaddr_bus(&info->cmd_ctrl.rngptr, (void *)0x100);
+	info->cmd_ctrl.flags = 0;
 	info->cmd_ctrl.max_len = 0;
 
 	for (i = 0; i < CMD_RING_ENTRIES; i++)
@@ -645,32 +787,51 @@
 
 	set_aceaddr(&info->stats2_ptr, &info->s.stats);
 
-	info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
 	set_aceaddr(&info->rx_std_ctrl.rngptr, ap->rx_std_ring);
-	info->rx_std_ctrl.flags = FLG_RX_TCP_UDP_SUM;
+	info->rx_std_ctrl.max_len = ACE_STD_MTU + ETH_HLEN + 4;
+	info->rx_std_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
 
 	memset(ap->rx_std_ring, 0,
 	       RX_STD_RING_ENTRIES * sizeof(struct rx_desc));
 
-	info->rx_jumbo_ctrl.max_len = 0;
+	for (i = 0; i < RX_STD_RING_ENTRIES; i++)
+		ap->rx_std_ring[i].flags = BD_FLG_TCP_UDP_SUM;
+
+	ap->rx_std_skbprd = 0;
+	atomic_set(&ap->cur_rx_bufs, 0);
+
 	set_aceaddr(&info->rx_jumbo_ctrl.rngptr, ap->rx_jumbo_ring);
-	info->rx_jumbo_ctrl.flags = FLG_RX_TCP_UDP_SUM;
+	info->rx_jumbo_ctrl.max_len = 0;
+	info->rx_jumbo_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
 
 	memset(ap->rx_jumbo_ring, 0,
 	       RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));
 
-	info->rx_mini_ctrl.max_len = 0;
-#if 0
-	set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring);
-#else
-	set_aceaddr_bus(&info->rx_mini_ctrl.rngptr, 0);
-#endif
-	info->rx_mini_ctrl.flags = FLG_RNG_DISABLED;
+	for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++)
+		ap->rx_jumbo_ring[i].flags = BD_FLG_TCP_UDP_SUM | BD_FLG_JUMBO;
+
+	ap->rx_jumbo_skbprd = 0;
+	atomic_set(&ap->cur_jumbo_bufs, 0);
 
-#if 0
 	memset(ap->rx_mini_ring, 0,
 	       RX_MINI_RING_ENTRIES * sizeof(struct rx_desc));
-#endif
+
+	if (ap->version >= 2) {
+		set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring);
+		info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
+		info->rx_mini_ctrl.flags = RCB_FLG_TCP_UDP_SUM;
+
+		for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
+			ap->rx_mini_ring[i].flags =
+				BD_FLG_TCP_UDP_SUM | BD_FLG_MINI;
+	} else {
+		set_aceaddr(&info->rx_mini_ctrl.rngptr, 0);
+		info->rx_mini_ctrl.flags = RCB_FLG_RNG_DISABLE;
+		info->rx_mini_ctrl.max_len = 0;
+	}
+
+	ap->rx_mini_skbprd = 0;
+	atomic_set(&ap->cur_mini_bufs, 0);
 
 	set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring);
 	info->rx_return_ctrl.flags = 0;
@@ -687,9 +848,13 @@
 		writel(0, (unsigned long)ap->tx_ring + i * 4);
 	}
 
+	set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE);
 	info->tx_ctrl.max_len = TX_RING_ENTRIES;
+#if TX_COAL_INTS_ONLY
+	info->tx_ctrl.flags = RCB_FLG_COAL_INT_ONLY;
+#else
 	info->tx_ctrl.flags = 0;
-	set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE);
+#endif
 
 	set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm);
 
@@ -743,7 +908,7 @@
 	 */
 	tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB |
 		LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE;
-	if(ap->version == 2)
+	if(ap->version >= 2)
 		tmp |= LNK_TX_FLOW_CTL_Y;
 
 	/*
@@ -780,28 +945,42 @@
 			       "negotiation\n", dev->name);
 		if (option & 0x200)
 			tmp |= LNK_RX_FLOW_CTL_Y;
-		if ((option & 0x400) && (ap->version == 2)){
+		if ((option & 0x400) && (ap->version >= 2)){
 			printk(KERN_INFO "%s: Enabling TX flow control\n",
 			       dev->name);
 			tmp |= LNK_TX_FLOW_CTL_Y;
 		}
 	}
 
+	ap->link = tmp;
 	writel(tmp, &regs->TuneLink);
-	if (ap->version == 2)
+	if (ap->version >= 2)
 		writel(tmp, &regs->TuneFastLink);
 
-	if (ap->version == 1)
+	if (ACE_IS_TIGON_I(ap))
 		writel(tigonFwStartAddr, &regs->Pc);
-	else if (ap->version == 2)
+	if (ap->version == 2)
 		writel(tigon2FwStartAddr, &regs->Pc);
 
 	writel(0, &regs->Mb0Lo);
 
 	/*
-	 * Start the NIC CPU
+	 * Set tx_csm before we start receiving interrupts, otherwise
+	 * the interrupt handler might think it is supposed to process
+	 * tx ints before we are up and running, which may cause a null
+	 * pointer access in the int handler.
 	 */
+	ap->tx_full = 0;
+	ap->cur_rx = 0;
+	ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0;
+
+	wmb();
+	writel(0, &regs->TxPrd);
+	writel(0, &regs->RxRetCsm);
 
+	/*
+	 * Start the NIC CPU
+	 */
 	writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
 
 	/*
@@ -820,8 +999,18 @@
 	 * We load the ring here as there seem to be no way to tell the
 	 * firmware to wipe the ring without re-initializing it.
 	 */
-	ace_load_std_rx_ring(dev);
-
+	if (!test_and_set_bit(0, &ap->std_refill_busy))
+		ace_load_std_rx_ring(ap, RX_RING_SIZE);
+	else
+		printk(KERN_ERR "%s: Someone is busy refilling the RX ring\n",
+		       dev->name);
+	if (ap->version >= 2) {
+		if (!test_and_set_bit(0, &ap->mini_refill_busy))
+			ace_load_mini_rx_ring(ap, RX_MINI_SIZE);
+		else
+			printk(KERN_ERR "%s: Someone is busy refilling "
+			       "the RX mini ring\n", dev->name);
+	}
 	return 0;
 }
 
@@ -850,6 +1039,44 @@
 }
 
 
+static void ace_bh(struct net_device *dev)
+{
+	struct ace_private *ap = dev->priv;
+	int cur_size;
+
+	cur_size = atomic_read(&ap->cur_rx_bufs);
+	if ((cur_size < RX_LOW_STD_THRES) &&
+	    !test_and_set_bit(0, &ap->std_refill_busy)) {
+#if DEBUG
+		printk("refilling buffers (current %i)\n", cur_size);
+#endif
+		ace_load_std_rx_ring(ap, RX_RING_SIZE - cur_size);
+	}
+
+	if (ap->version >= 2) {
+		cur_size = atomic_read(&ap->cur_mini_bufs);
+		if ((cur_size < RX_LOW_MINI_THRES) &&
+		    !test_and_set_bit(0, &ap->mini_refill_busy)) {
+#if DEBUG
+			printk("refilling mini buffers (current %i)\n",
+			       cur_size);
+#endif
+			ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size);
+		}
+	}
+
+	cur_size = atomic_read(&ap->cur_jumbo_bufs);
+	if (ap->jumbo && (cur_size < RX_LOW_JUMBO_THRES) &&
+	    !test_and_set_bit(0, &ap->jumbo_refill_busy)) {
+#if DEBUG
+		printk("refilling jumbo buffers (current %i)\n", >cur_size);
+#endif
+		ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size);
+	}
+	ap->bh_pending = 0;
+}
+
+
 /*
  * Copy the contents of the NIC's trace buffer to kernel memory.
  */
@@ -865,69 +1092,92 @@
 
 /*
  * Load the standard rx ring.
+ *
+ * Loading rings is safe without holding the spin lock since this is
+ * done only before the device is enabled, thus no interrupts are
+ * generated and by the interrupt handler/bh handler.
  */
-static int ace_load_std_rx_ring(struct net_device *dev)
+static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
 {
-	struct ace_private *ap;
 	struct ace_regs *regs;
-	struct ace_info *info;
-	unsigned long flags;
-	struct cmd cmd;
-	short i;
+	short i, idx;
 
-	ap = (struct ace_private *)dev->priv;
 	regs = ap->regs;
-	info = ap->info;
-
-	spin_lock_irqsave(&ap->lock, flags);
 
-	/*
-	 * Set tx_csm before we start receiving interrupts, otherwise
-	 * the interrupt handler might think it is supposed to process
-	 * tx ints before we are up and running, which may cause a null
-	 * pointer access in the int handler.
-	 */
-	ap->tx_full = 0;
-	ap->cur_rx = ap->dirty_rx = 0;
-	ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0;
-	writel(0, &regs->RxRetCsm);
+	idx = ap->rx_std_skbprd;
 
-	for (i = 0; i < RX_RING_THRESH; i++) {
+	for (i = 0; i < nr_bufs; i++) {
 		struct sk_buff *skb;
+		struct rx_desc *rd;
 
-		ap->rx_std_ring[i].flags = 0;
-		skb = alloc_skb(ACE_STD_MTU + ETH_HLEN + 6, GFP_ATOMIC);
-		ap->rx_std_skbuff[i] = skb;
-
+		skb = alloc_skb(ACE_STD_BUFSIZE, GFP_ATOMIC);
 		/*
-		 * Make sure the data contents end up on an aligned address
+		 * Make sure IP header starts on a fresh cache line.
 		 */
-		skb_reserve(skb, 2);
+		skb_reserve(skb, 2 + 16);
+		ap->skb->rx_std_skbuff[idx] = skb;
 
-		set_aceaddr(&ap->rx_std_ring[i].addr, skb->data);
-		ap->rx_std_ring[i].size = ACE_STD_MTU + ETH_HLEN + 4;
+		rd = &ap->rx_std_ring[idx];
+		set_aceaddr(&rd->addr, skb->data);
+		rd->size = ACE_STD_MTU + ETH_HLEN + 4;
+		rd->idx = idx;
+		idx = (idx + 1) % RX_STD_RING_ENTRIES;
+	}
+
+	atomic_add(nr_bufs, &ap->cur_rx_bufs);
+	ap->rx_std_skbprd = idx;
+
+	if (ACE_IS_TIGON_I(ap)) {
+		struct cmd cmd;
+		cmd.evt = C_SET_RX_PRD_IDX;
+		cmd.code = 0;
+		cmd.idx = ap->rx_std_skbprd;
+		ace_issue_cmd(regs, &cmd);
+	} else {
+		writel(idx, &regs->RxStdPrd);
+		wmb();
+	}
 
-		ap->rx_std_ring[i].flags = 0;
-		ap->rx_std_ring[i].type = DESC_RX;
+	clear_bit(0, &ap->std_refill_busy);
+	return;
+}
 
-		ap->rx_std_ring[i].idx = i;
-	}
 
-	ap->rx_std_skbprd = i;
+static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs)
+{
+	struct ace_regs *regs;
+	short i, idx;
+
+	regs = ap->regs;
 
-	/*
-	 * The last descriptor needs to be marked as being special.
-	 */
-	ap->rx_std_ring[i-1].type = DESC_END;
+	idx = ap->rx_mini_skbprd;
+	for (i = 0; i < nr_bufs; i++) {
+		struct sk_buff *skb;
+		struct rx_desc *rd;
 
-	cmd.evt = C_SET_RX_PRD_IDX;
-	cmd.code = 0;
-	cmd.idx = ap->rx_std_skbprd;
-	ace_issue_cmd(regs, &cmd);
+		skb = alloc_skb(ACE_MINI_BUFSIZE, GFP_ATOMIC);
+		/*
+		 * Make sure the IP header ends up on a fresh cache line
+		 */
+		skb_reserve(skb, 2 + 16);
+		ap->skb->rx_mini_skbuff[idx] = skb;
 
-	spin_unlock_irqrestore(&ap->lock, flags);
+		rd = &ap->rx_mini_ring[idx];
+		set_aceaddr(&rd->addr, skb->data);
+		rd->size = ACE_MINI_SIZE;
+		rd->idx = idx;
+		idx = (idx + 1) % RX_MINI_RING_ENTRIES;
+	}
 
-	return 0;
+	atomic_add(nr_bufs, &ap->cur_mini_bufs);
+
+	ap->rx_mini_skbprd = idx;
+
+	writel(idx, &regs->RxMiniPrd);
+	wmb();
+
+	clear_bit(0, &ap->mini_refill_busy);
+	return;
 }
 
 
@@ -935,61 +1185,54 @@
  * Load the jumbo rx ring, this may happen at any time if the MTU
  * is changed to a value > 1500.
  */
-static int ace_load_jumbo_rx_ring(struct net_device *dev)
+static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs)
 {
-	struct ace_private *ap;
 	struct ace_regs *regs;
-	struct cmd cmd;
-	unsigned long flags;
-	short i;
+	short i, idx;
 
-	ap = (struct ace_private *)dev->priv;
 	regs = ap->regs;
 
-	spin_lock_irqsave(&ap->lock, flags);
+	idx = ap->rx_jumbo_skbprd;
 
-	for (i = 0; i < RX_RING_JUMBO_THRESH; i++) {
+	for (i = 0; i < nr_bufs; i++) {
 		struct sk_buff *skb;
+		struct rx_desc *rd;
 
-		ap->rx_jumbo_ring[i].flags = 0;
-		skb = alloc_skb(ACE_JUMBO_MTU + ETH_HLEN + 6, GFP_ATOMIC);
-		ap->rx_jumbo_skbuff[i] = skb;
-
+		skb = alloc_skb(ACE_JUMBO_BUFSIZE, GFP_ATOMIC);
 		/*
-		 * Make sure the data contents end up on an aligned address
+		 * Make sure the IP header ends up on a fresh cache line
 		 */
-		skb_reserve(skb, 2);
-
-		set_aceaddr(&ap->rx_jumbo_ring[i].addr, skb->data);
-		ap->rx_jumbo_ring[i].size = ACE_JUMBO_MTU + ETH_HLEN + 4;
+		skb_reserve(skb, 2 + 16);
+		ap->skb->rx_jumbo_skbuff[idx] = skb;
 
-		ap->rx_jumbo_ring[i].flags = DFLG_RX_JUMBO;
-		ap->rx_jumbo_ring[i].type = DESC_RX;
-
-		ap->rx_jumbo_ring[i].idx = i;
+		rd = &ap->rx_jumbo_ring[idx];
+		set_aceaddr(&rd->addr, skb->data);
+		rd->size = ACE_JUMBO_MTU + ETH_HLEN + 4;
+		rd->idx = idx;
+		idx = (idx + 1) % RX_JUMBO_RING_ENTRIES;
+	}
+
+	atomic_add(nr_bufs, &ap->cur_jumbo_bufs);
+	ap->rx_jumbo_skbprd = idx;
+
+	if (ACE_IS_TIGON_I(ap)) {
+		struct cmd cmd;
+		cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
+		cmd.code = 0;
+		cmd.idx = ap->rx_jumbo_skbprd;
+		ace_issue_cmd(regs, &cmd);
+	} else {
+		writel(idx, &regs->RxJumboPrd);
+		wmb();
 	}
 
-	ap->rx_jumbo_skbprd = i;
-
-	/*
-	 * The last descriptor needs to be marked as being special.
-	 */
-	ap->rx_jumbo_ring[i-1].type = DESC_END;
-
-	cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
-	cmd.code = 0;
-	cmd.idx = ap->rx_jumbo_skbprd;
-	ace_issue_cmd(regs, &cmd);
-
-	spin_unlock_irqrestore(&ap->lock, flags);
-
-	return 0;
+	clear_bit(0, &ap->jumbo_refill_busy);
+	return;
 }
 
 
 /*
  * Tell the firmware not to accept jumbos and flush the jumbo ring.
- * This function must be called with the spinlock held.
  */
 static int ace_flush_jumbo_rx_ring(struct net_device *dev)
 {
@@ -1008,10 +1251,10 @@
 		ace_issue_cmd(regs, &cmd);
 
 		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {
-			if (ap->rx_jumbo_skbuff[i]) {
+			if (ap->skb->rx_jumbo_skbuff[i]) {
 				ap->rx_jumbo_ring[i].size = 0;
 				set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0);
-				dev_kfree_skb(ap->rx_jumbo_skbuff[i]);
+				dev_kfree_skb(ap->skb->rx_jumbo_skbuff[i]);
 			}
 		}
 	}else
@@ -1046,13 +1289,14 @@
 		{
 			u16 code = ap->evt_ring[evtcsm].code;
 			if (code == E_C_LINK_UP){
-				printk("%s: Optical link UP\n", dev->name);
+				printk(KERN_WARNING "%s: Optical link UP\n",
+				       dev->name);
 			}
 			else if (code == E_C_LINK_DOWN)
-				printk(KERN_INFO "%s: Optical link DOWN\n",
+				printk(KERN_WARNING "%s: Optical link DOWN\n",
 				       dev->name);
 			else
-				printk(KERN_INFO "%s: Unknown optical link "
+				printk(KERN_ERR "%s: Unknown optical link "
 				       "state %02x\n", dev->name, code);
 			break;
 		}
@@ -1088,100 +1332,65 @@
 }
 
 
-static int ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
+static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 {
 	struct ace_private *ap = (struct ace_private *)dev->priv;
-	struct ace_regs *regs = ap->regs;
-	u32 idx, oldidx;
+	u32 idx;
+	int mini_count = 0, std_count = 0;
 
 	idx = rxretcsm;
 
 	while (idx != rxretprd){
-		struct sk_buff *skb, *newskb, *oldskb;
-		struct rx_desc *newrxdesc, *oldrxdesc;
-		u32 prdidx, size;
-		void *addr;
+		struct sk_buff *skb, **oldskb_p;
+		struct rx_desc *rxdesc;
+		u32 skbidx;
+		int desc_type;
 		u16 csum;
-		int jumbo;
-
-		oldidx = ap->rx_return_ring[idx].idx;
-		jumbo = ap->rx_return_ring[idx].flags & DFLG_RX_JUMBO;
-
-		if (jumbo){
-			oldskb = ap->rx_jumbo_skbuff[oldidx];
-			prdidx = ap->rx_jumbo_skbprd;
-			newrxdesc = &ap->rx_jumbo_ring[prdidx];
-			oldrxdesc = &ap->rx_jumbo_ring[oldidx];
-		}else{
-			oldskb = ap->rx_std_skbuff[oldidx];
-			prdidx = ap->rx_std_skbprd;
-			newrxdesc = &ap->rx_std_ring[prdidx];
-			oldrxdesc = &ap->rx_std_ring[oldidx];
-		}
-
-		size = oldrxdesc->size;
-
-		if (size < PKT_COPY_THRESHOLD) {
-			skb = alloc_skb(size + 2, GFP_ATOMIC);
-			if (skb == NULL){
-				printk(KERN_ERR "%s: Out of memory\n",
-				       dev->name);
-				goto error;
-			}
-			/*
-			 * Make sure the real data is aligned
-			 */
 
-			skb_reserve(skb, 2);
-			memcpy(skb_put(skb, size), oldskb->data, size);
-			addr = get_aceaddr_bus(&oldrxdesc->addr);
-			newskb = oldskb;
-		}else{
-			skb = oldskb;
-
-			skb_put(skb, size);
-
-			newskb = alloc_skb(size + 2, GFP_ATOMIC);
-			if (newskb == NULL){
-				printk(KERN_ERR "%s: Out of memory\n",
-				       dev->name);
-				goto error;
-			}
+		skbidx = ap->rx_return_ring[idx].idx;
+		desc_type = ap->rx_return_ring[idx].flags &
+			(BD_FLG_JUMBO | BD_FLG_MINI);
 
+		switch(desc_type) {
 			/*
-			 * Make sure we DMA directly into nicely
-			 * aligned receive buffers
+			 * Normal frames do not have any flags set
+			 *
+			 * Mini and normal frames arrive frequently,
+			 * so use a local counter to avoid doing
+			 * atomic operations for each packet arriving.
 			 */
-			skb_reserve(newskb, 2);
-			addr = (void *)virt_to_bus(newskb->data);
-		}
-
-		set_aceaddr_bus(&newrxdesc->addr, addr);
-		newrxdesc->size = size;
-
-		newrxdesc->flags = oldrxdesc->flags;
-		newrxdesc->idx = prdidx;
-		newrxdesc->type = DESC_RX;
-#if (BITS_PER_LONG == 32)
-		newrxdesc->addr.addrhi = 0;
-#endif
-
-		oldrxdesc->size = 0;
-		set_aceaddr_bus(&oldrxdesc->addr, 0);
-
-		if (jumbo){
-			ap->rx_jumbo_skbuff[oldidx] = NULL;
-			ap->rx_jumbo_skbuff[prdidx] = newskb;
-
-			prdidx = (prdidx + 1) % RX_JUMBO_RING_ENTRIES;
-			ap->rx_jumbo_skbprd = prdidx;
-		}else{
-			ap->rx_std_skbuff[oldidx] = NULL;
-			ap->rx_std_skbuff[prdidx] = newskb;
-
-			prdidx = (prdidx + 1) % RX_STD_RING_ENTRIES;
-			ap->rx_std_skbprd = prdidx;
-		}
+		case 0:
+			oldskb_p = &ap->skb->rx_std_skbuff[skbidx];
+			rxdesc = &ap->rx_std_ring[skbidx];
+			std_count++;
+			break;
+		case BD_FLG_JUMBO:
+			oldskb_p = &ap->skb->rx_jumbo_skbuff[skbidx];
+			rxdesc = &ap->rx_jumbo_ring[skbidx];
+			atomic_dec(&ap->cur_jumbo_bufs);
+			break;
+		case BD_FLG_MINI:
+			oldskb_p = &ap->skb->rx_mini_skbuff[skbidx];
+			rxdesc = &ap->rx_mini_ring[skbidx];
+			mini_count++; 
+			break;
+		default:
+			printk(KERN_INFO "%s: unknown frame type (0x%02x) "
+			       "returned by NIC\n", dev->name,
+			       ap->rx_return_ring[idx].flags);
+			goto error;
+		}
+
+		skb = *oldskb_p;
+#if DEBUG
+		if (skb == NULL) {
+			printk("Mayday! illegal skb received! (idx %i)\n", skbidx);
+			goto error;
+		}
+#endif
+		*oldskb_p = NULL;
+		skb_put(skb, rxdesc->size);
+		rxdesc->size = 0;
 
 		/*
 		 * Fly baby, fly!
@@ -1191,12 +1400,6 @@
 		skb->dev = dev;
 		skb->protocol = eth_type_trans(skb, dev);
 
-#if 0
-		/*
-		 * This was never actually enabled in the RX descriptors
-		 * anyway - it requires a bit more testing before enabling
-		 * it again.
-		 */
 		/*
 		 * If the checksum is correct and this is not a
 		 * fragment, tell the stack that the data is correct.
@@ -1207,34 +1410,31 @@
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 		else
 			skb->ip_summed = CHECKSUM_NONE;
-#endif
+
 		netif_rx(skb);		/* send it up */
 
 		ap->stats.rx_packets++;
 		ap->stats.rx_bytes += skb->len;
 
-		if ((prdidx & 0x7) == 0){
-			struct cmd cmd;
-			if (jumbo)
-				cmd.evt = C_SET_RX_JUMBO_PRD_IDX;
-			else
-				cmd.evt = C_SET_RX_PRD_IDX;
-			cmd.code = 0;
-			cmd.idx = prdidx;
-			ace_issue_cmd(regs, &cmd);
-		}
-
 		idx = (idx + 1) % RX_RETURN_RING_ENTRIES;
 	}
+
+	atomic_sub(std_count, &ap->cur_rx_bufs);
+	if (!ACE_IS_TIGON_I(ap))
+		atomic_sub(mini_count, &ap->cur_mini_bufs);
+
  out:
 	/*
 	 * According to the documentation RxRetCsm is obsolete with
-	 * the 12.3.x Firmware - my Tigon I NIC's seem to disagree!
+	 * the 12.3.x Firmware - my Tigon I NICs seem to disagree!
 	 */
-	writel(idx, &regs->RxRetCsm);
+	if (ACE_IS_TIGON_I(ap)) {
+		struct ace_regs *regs = ap->regs;
+		writel(idx, &regs->RxRetCsm);
+	}
 	ap->cur_rx = idx;
 
-	return idx;
+	return;
  error:
 	idx = rxretprd;
 	goto out;
@@ -1246,23 +1446,20 @@
 	struct ace_private *ap;
 	struct ace_regs *regs;
 	struct net_device *dev = (struct net_device *)dev_id;
+	u32 idx;
 	u32 txcsm, rxretcsm, rxretprd;
 	u32 evtcsm, evtprd;
 
 	ap = (struct ace_private *)dev->priv;
 	regs = ap->regs;
 
-	spin_lock(&ap->lock);
-
 	/*
 	 * In case of PCI shared interrupts or spurious interrupts,
 	 * we want to make sure it is actually our interrupt before
 	 * spending any time in here.
 	 */
-	if (!(readl(&regs->HostCtrl) & IN_INT)){
-		spin_unlock(&ap->lock);
+	if (!(readl(&regs->HostCtrl) & IN_INT))
 		return;
-	}
 
 	/*
 	 * Tell the card not to generate interrupts while we are in here.
@@ -1270,25 +1467,35 @@
 	writel(1, &regs->Mb0Lo);
 
 	/*
-	 * Service RX ints before TX
+	 * There is no conflict between transmit handling in
+	 * start_xmit and receive processing, thus there is no reason
+	 * to take a spin lock for RX handling. Wait until we start
+	 * working on the other stuff - hey we don't need a spin lock
+	 * anymore.
 	 */
 	rxretprd = ap->rx_ret_prd;
 	rxretcsm = ap->cur_rx;
 
 	if (rxretprd != rxretcsm)
-		rxretprd = ace_rx_int(dev, rxretprd, rxretcsm);
+		ace_rx_int(dev, rxretprd, rxretcsm);
 
 	txcsm = ap->tx_csm;
-	if (txcsm != ap->tx_ret_csm) {
-		u32 idx = ap->tx_ret_csm;
+	idx = ap->tx_ret_csm;
 
+	if (txcsm != idx) {
 		do {
 			ap->stats.tx_packets++;
-			ap->stats.tx_bytes += ap->tx_skbuff[idx]->len;
-			dev_kfree_skb(ap->tx_skbuff[idx]);
+			ap->stats.tx_bytes += ap->skb->tx_skbuff[idx]->len;
+			dev_kfree_skb(ap->skb->tx_skbuff[idx]);
 
-			ap->tx_skbuff[idx] = NULL;
+			ap->skb->tx_skbuff[idx] = NULL;
 
+			/*
+			 * Question here is whether one should not skip
+			 * these writes - I have never seen any errors
+			 * caused by the NIC actually trying to access
+			 * these incorrectly.
+			 */
 #if (BITS_PER_LONG == 64)
 			writel(0, &ap->tx_ring[idx].addr.addrhi);
 #endif
@@ -1298,10 +1505,19 @@
 			idx = (idx + 1) % TX_RING_ENTRIES;
 		} while (idx != txcsm);
 
-		if (ap->tx_full && dev->tbusy &&
-		    (((ap->tx_prd + 1) % TX_RING_ENTRIES) != txcsm)){
+		/*
+		 * Once we actually get to this point the tx ring has
+		 * already been trimmed thus it cannot be full!
+		 * Ie. skip the comparison of the tx producer vs. the
+		 * consumer.
+		 */
+		if (ap->tx_full && dev->tbusy) {
 			ap->tx_full = 0;
-			dev->tbusy = 0;
+			/*
+			 * This does not need to be atomic (and expensive),
+			 * I've seen cases where it would fail otherwise ;-(
+			 */
+			clear_bit(0, &dev->tbusy);
 			mark_bh(NET_BH);
 
 			/*
@@ -1312,19 +1528,80 @@
 		}
 
 		ap->tx_ret_csm = txcsm;
+		wmb();
 	}
 
 	evtcsm = readl(&regs->EvtCsm);
 	evtprd = ap->evt_prd;
 
-	if (evtcsm != evtprd){
+	if (evtcsm != evtprd) {
 		evtcsm = ace_handle_event(dev, evtcsm, evtprd);
+		writel(evtcsm, &regs->EvtCsm);
 	}
 
-	writel(evtcsm, &regs->EvtCsm);
-	writel(0, &regs->Mb0Lo);
+	/*
+	 * This has to go last in the interrupt handler and run with
+	 * the spin lock released ... what lock?
+	 */
+	if (dev->start) {
+		int cur_size;
+		int run_bh = 0;
 
-	spin_unlock(&ap->lock);
+		cur_size = atomic_read(&ap->cur_rx_bufs);
+		if (cur_size < RX_LOW_STD_THRES) {
+			if ((cur_size < RX_PANIC_STD_THRES) &&
+			    !test_and_set_bit(0, &ap->std_refill_busy)) {
+#if DEBUG
+				printk("low on std buffers %i\n", cur_size);
+#endif
+				ace_load_std_rx_ring(ap,
+						     RX_RING_SIZE - cur_size);
+			}
+				run_bh = 1;
+		}
+
+		if (!ACE_IS_TIGON_I(ap)) {
+			cur_size = atomic_read(&ap->cur_mini_bufs);
+			if (cur_size < RX_LOW_MINI_THRES) {
+				if ((cur_size < RX_PANIC_MINI_THRES) &&
+				    !test_and_set_bit(0,
+						      &ap->mini_refill_busy)) {
+#if DEBUG
+					printk("low on mini buffers %i\n",
+					       cur_size);
+#endif
+					ace_load_mini_rx_ring(ap, RX_MINI_SIZE - cur_size);
+				} else
+					run_bh = 1;
+			}
+		}
+
+		if (ap->jumbo) {
+			cur_size = atomic_read(&ap->cur_jumbo_bufs);
+			if (cur_size < RX_LOW_JUMBO_THRES) {
+				if ((cur_size < RX_PANIC_JUMBO_THRES) &&
+				    !test_and_set_bit(0,
+						      &ap->jumbo_refill_busy)){
+#if DEBUG
+					printk("low on jumbo buffers %i\n",
+					       cur_size);
+#endif
+					ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE - cur_size);
+				} else
+					run_bh = 1;
+			}
+		}
+		if (run_bh && !ap->bh_pending) {
+			ap->bh_pending = 1;
+			queue_task(&ap->immediate, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		}
+	}
+
+	/*
+	 * Allow the card to generate interrupts again
+	 */
+	writel(0, &regs->Mb0Lo);
 }
 
 
@@ -1338,7 +1615,7 @@
 	regs = ap->regs;
 
 	if (!(ap->fw_running)){
-		printk(KERN_WARNING "%s: firmware not running!\n", dev->name);
+		printk(KERN_WARNING "%s: Firmware not running!\n", dev->name);
 		return -EBUSY;
 	}
 
@@ -1349,8 +1626,9 @@
 	cmd.idx = 0;
 	ace_issue_cmd(regs, &cmd);
 
-	if (ap->jumbo)
-		ace_load_jumbo_rx_ring(dev);
+	if (ap->jumbo &&
+	    !test_and_set_bit(0, &ap->jumbo_refill_busy))
+		ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
 
 	if (dev->flags & IFF_PROMISC){
 		cmd.evt = C_SET_PROMISC_MODE;
@@ -1364,10 +1642,6 @@
 	ap->mcast_all = 0;
 
 #if 0
-	{ long myjif = jiffies + HZ;
-	while (time_before(jiffies, myjif));
-	}
-
 	cmd.evt = C_LNK_NEGOTIATION;
 	cmd.code = 0;
 	cmd.idx = 0;
@@ -1386,6 +1660,15 @@
 	init_timer(&ap->timer);
 	ap->timer.data = (unsigned long)dev;
 	ap->timer.function = ace_timer;
+
+	/*
+	 * Setup the bottom half rx ring refill handler
+	 */
+	ap->immediate.next = NULL;
+	ap->immediate.sync = 0;
+	ap->immediate.routine = (void *)(void *)ace_bh;
+	ap->immediate.data = dev;
+
 	return 0;
 }
 
@@ -1399,7 +1682,7 @@
 	short i;
 
 	dev->start = 0;
-	set_bit(0, (void*)&dev->tbusy);
+	set_bit(0, &dev->tbusy);
 
 	ap = (struct ace_private *)dev->priv;
 	regs = ap->regs;
@@ -1419,21 +1702,26 @@
 	cmd.idx = 0;
 	ace_issue_cmd(regs, &cmd);
 
-	spin_lock_irqsave(&ap->lock, flags);
+	/*
+	 * Make sure one CPU is not processing packets while
+	 * buffers are being released by another.
+	 */
+	save_flags(flags);
+	cli();
 
 	for (i = 0; i < TX_RING_ENTRIES; i++) {
-		if (ap->tx_skbuff[i]) {
+		if (ap->skb->tx_skbuff[i]) {
 			writel(0, &ap->tx_ring[i].addr.addrhi);
 			writel(0, &ap->tx_ring[i].addr.addrlo);
 			writel(0, &ap->tx_ring[i].flagsize);
-			dev_kfree_skb(ap->tx_skbuff[i]);
+			dev_kfree_skb(ap->skb->tx_skbuff[i]);
 		}
 	}
 
 	if (ap->jumbo)
 		ace_flush_jumbo_rx_ring(dev);
 
-	spin_unlock_irqrestore(&ap->lock, flags);
+	restore_flags(flags);
 
 	MOD_DEC_USE_COUNT;
 	return 0;
@@ -1444,31 +1732,44 @@
 {
 	struct ace_private *ap = (struct ace_private *)dev->priv;
 	struct ace_regs *regs = ap->regs;
-	unsigned long flags;
 	unsigned long addr;
 	u32 idx, flagsize;
 
-	spin_lock_irqsave(&ap->lock, flags);
+	if (test_and_set_bit(0, &dev->tbusy))
+		return 1;
 
 	idx = ap->tx_prd;
 
-	ap->tx_skbuff[idx] = skb;
+	if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm) {
+		ap->tx_full = 1;
+#if DEBUG
+		printk("%s: trying to transmit while the tx ring is full "
+		       "- this should not happen!\n", dev->name);
+#endif
+		return 1;
+	}
+
+	ap->skb->tx_skbuff[idx] = skb;
 	addr = virt_to_bus(skb->data);
 #if (BITS_PER_LONG == 64)
 	writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
 #endif
 	writel(addr & 0xffffffff, &ap->tx_ring[idx].addr.addrlo);
-	flagsize = (skb->len << 16) | (DESC_END) ;
+	flagsize = (skb->len << 16) | (BD_FLG_END) ;
 	writel(flagsize, &ap->tx_ring[idx].flagsize);
-	mb();
+	wmb();
 	idx = (idx + 1) % TX_RING_ENTRIES;
 
 	ap->tx_prd = idx;
 	writel(idx, &regs->TxPrd);
+	wmb();
 
-	if ((idx + 1) % TX_RING_ENTRIES == ap->tx_ret_csm){
+	/*
+	 * tx_csm is set by the NIC whereas we set tx_ret_csm which
+	 * is always trying to catch tx_csm
+	 */
+	if ((idx + 2) % TX_RING_ENTRIES == ap->tx_ret_csm){
 		ap->tx_full = 1;
-		set_bit(0, (void*)&dev->tbusy);
 		/*
 		 * Queue is full, add timer to detect whether the
 		 * transmitter is stuck. Use mod_timer as we can get
@@ -1476,10 +1777,13 @@
 		 * timers.
 		 */
 		mod_timer(&ap->timer, jiffies + (3 * HZ));
+	} else {
+		/*
+		 * No need for it to be atomic - seems it needs to be
+		 */
+		clear_bit(0, &dev->tbusy);
 	}
 
-	spin_unlock_irqrestore(&ap->lock, flags);
-
 	dev->trans_start = jiffies;
 	return 0;
 }
@@ -1501,7 +1805,8 @@
 			printk(KERN_INFO "%s: Enabling Jumbo frame "
 			       "support\n", dev->name);
 			ap->jumbo = 1;
-			ace_load_jumbo_rx_ring(dev);
+			if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
+				ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
 		}
 		ap->jumbo = 1;
 	}else{
@@ -1518,6 +1823,126 @@
 }
 
 
+static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+#ifdef ETHTOOL
+	struct ace_private *ap = (struct ace_private *) dev->priv;
+	struct ace_regs *regs = ap->regs;
+	struct ethtool_cmd ecmd;
+	u32 link, speed;
+
+	if (cmd != SIOCETHTOOL)
+		return -EOPNOTSUPP;
+	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
+		return -EFAULT;
+
+	if (ecmd.cmd == ETH_GSET) {
+		ecmd.supported =
+			(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
+			 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
+			 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full |
+			 SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+
+		ecmd.port = PORT_FIBRE;
+		ecmd.transceiver = XCVR_INTERNAL;
+		ecmd.phy_address = 0;
+
+		link = readl(&regs->GigLnkState);
+		if (link & LNK_1000MB)
+			ecmd.speed = SPEED_1000;
+		else {
+			link = readl(&regs->FastLnkState);
+			if (link & LNK_100MB)
+				ecmd.speed = SPEED_100;
+			else if (link & LNK_100MB)
+				ecmd.speed = SPEED_10;
+			else
+				ecmd.speed = 0;
+		}
+		if (link & LNK_FULL_DUPLEX)
+			ecmd.duplex = DUPLEX_FULL;
+		else
+			ecmd.duplex = DUPLEX_HALF;
+
+		if (link & LNK_NEGOTIATE)
+			ecmd.autoneg = AUTONEG_ENABLE;
+		else
+			ecmd.autoneg = AUTONEG_DISABLE;
+
+		ecmd.trace = readl(&regs->TuneTrace);
+
+		ecmd.txcoal = readl(&regs->TuneTxCoalTicks);
+		ecmd.rxcoal = readl(&regs->TuneRxCoalTicks);
+		ecmd.maxtxpkt = readl(&regs->TuneMaxTxDesc);
+		ecmd.maxrxpkt = readl(&regs->TuneMaxRxDesc);
+
+		if(copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return 0;
+	} else if (ecmd.cmd == ETH_SSET) {
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		link = readl(&regs->GigLnkState);
+		if (link & LNK_1000MB)
+			speed = SPEED_1000;
+		else {
+			link = readl(&regs->FastLnkState);
+			if (link & LNK_100MB)
+				speed = SPEED_100;
+			else if (link & LNK_100MB)
+				speed = SPEED_10;
+			else
+				speed = SPEED_100;
+		}
+
+		link = LNK_ENABLE | LNK_1000MB | LNK_100MB | LNK_10MB |
+			LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL;
+		if (!ACE_IS_TIGON_I(ap))
+			link |= LNK_TX_FLOW_CTL_Y;
+		if (ecmd.autoneg == AUTONEG_ENABLE)
+			link |= LNK_NEGOTIATE;
+		if (ecmd.speed != speed) {
+			link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB);
+			switch (speed) {
+			case SPEED_1000:
+				link |= LNK_1000MB;
+				break;
+			case SPEED_100:
+				link |= LNK_100MB;
+				break;
+			case SPEED_10:
+				link |= LNK_10MB;
+				break;
+			}
+		}
+		if (ecmd.duplex == DUPLEX_FULL)
+			link |= LNK_FULL_DUPLEX;
+
+		if (link != ap->link) {
+			struct cmd cmd;
+			printk(KERN_INFO "%s: Renegotiating link state\n",
+			       dev->name);
+
+			ap->link = link;
+			writel(link, &regs->TuneLink);
+			if (!ACE_IS_TIGON_I(ap))
+				writel(link, &regs->TuneFastLink);
+			wmb();
+
+			cmd.evt = C_LNK_NEGOTIATION;
+			cmd.code = 0;
+			cmd.idx = 0;
+			ace_issue_cmd(regs, &cmd);
+		}
+		return 0;
+	}
+#endif
+
+	return -EOPNOTSUPP;
+}
+
+
 /*
  * Set the hardware MAC address.
  */
@@ -1530,6 +1955,7 @@
 
 	if(dev->start)
 		return -EBUSY;
+
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
 
 	da = (u16 *)dev->dev_addr;
@@ -1627,9 +2053,6 @@
 #ifdef __BIG_ENDIAN
 #error "data must be swapped here"
 #else
-/*
- * XXX - special memcpy needed here!!!
- */
 		wsrc = src;
 		for (i = 0; i < (tsize / 4); i++){
 			writel(wsrc[i], tdest + i*4);
@@ -1696,7 +2119,7 @@
 	 * funny things on NICs with only 512KB SRAM
 	 */
 	ace_clear(regs, 0x2000, 0x80000-0x2000);
-	if (ap->version == 1){
+	if (ACE_IS_TIGON_I(ap)){
 		ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen);
 		ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen);
 		ace_copy(regs, tigonFwRodata, tigonFwRodataAddr,
@@ -1728,7 +2151,7 @@
  *
  * Oh yes, this is only the beginning!
  */
-static void eeprom_start(struct ace_regs *regs)
+static void __init eeprom_start(struct ace_regs *regs)
 {
 	u32 local = readl(&regs->LocalCtrl);
 
@@ -1751,7 +2174,7 @@
 }
 
 
-static void eeprom_prep(struct ace_regs *regs, u8 magic)
+static void __init eeprom_prep(struct ace_regs *regs, u8 magic)
 {
 	short i;
 	u32 local;
@@ -1784,7 +2207,7 @@
 }
 
 
-static int eeprom_check_ack(struct ace_regs *regs)
+static int __init eeprom_check_ack(struct ace_regs *regs)
 {
 	int state;
 	u32 local;
@@ -1809,7 +2232,7 @@
 }
 
 
-static void eeprom_stop(struct ace_regs *regs)
+static void __init eeprom_stop(struct ace_regs *regs)
 {
 	u32 local;
 
@@ -1839,7 +2262,7 @@
 /*
  * Read a whole byte from the EEPROM.
  */
-static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset)
+static u8 __init read_eeprom_byte(struct ace_regs *regs, unsigned long offset)
 {
 	u32 local;
 	short i;
@@ -1911,6 +2334,6 @@
 
 /*
  * Local variables:
- * compile-command: "gcc -D__KERNEL__ -D__SMP__ -DMODULE -I/data/home/jes/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include /data/home/jes/linux/include/linux/modversions.h   -c -o acenic.o acenic.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h   -c -o acenic.o acenic.c"
  * End:
  */
diff -u --recursive --new-file v2.3.16/linux/drivers/net/acenic.h linux/drivers/net/acenic.h
--- v2.3.16/linux/drivers/net/acenic.h	Wed Aug 18 11:36:45 1999
+++ linux/drivers/net/acenic.h	Sat Sep  4 13:11:36 1999
@@ -14,7 +14,7 @@
  * as some of them are in PCI shared memory and it is necessary to use
  * readl/writel to access them.
  *
- * The addressing code is derived from Pete Beckman's work, but
+ * The addressing code is derived from Pete Wyckoff's work, but
  * modified to deal properly with readl/writel usage.
  */
 
@@ -143,11 +143,11 @@
 	u32	Mb2Hi;
 	u32	TxPrd;
 	u32	Mb3Hi;
-	u32	Mb3Lo;
+	u32	RxStdPrd; /* RxStdPrd */
 	u32	Mb4Hi;
-	u32	Mb4Lo;
+	u32	RxJumboPrd; /* RxJumboPrd */
 	u32	Mb5Hi;
-	u32	Mb5Lo;
+	u32	RxMiniPrd;
 	u32	Mb6Hi;
 	u32	Mb6Lo;
 	u32	Mb7Hi;
@@ -197,7 +197,7 @@
 	u32	IfIdx;
 	u32	IfMtu;		/* 0x660 */
 	u32	MaskInt;
-	u32	LnkState;
+	u32	GigLnkState;
 	u32	FastLnkState;
 	u32	pad16[4];	/* 0x670 */
 	u32	RxRetCsm;	/* 0x680 */
@@ -279,6 +279,7 @@
 #define DMA_WRITE_MAX_256	0xc0
 #define DMA_WRITE_MAX_1K	0xe0
 #define MEM_READ_MULTIPLE	0x00020000
+#define PCI_66MHZ		0x00080000
 #define DMA_WRITE_ALL_ALIGN	0x00800000
 #define READ_CMD_MEM		0x06000000
 #define WRITE_CMD_MEM		0x70000000
@@ -365,6 +366,7 @@
 #define E_LNK_STATE		0x06
 #define E_C_LINK_UP		0x01
 #define E_C_LINK_DOWN		0x02
+#define E_C_LINK_UP_FAST	0x03
 
 #define E_ERROR			0x07
 #define E_C_ERR_INVAL_CMD	0x01
@@ -416,6 +418,10 @@
 #define C_C_PROMISC_DISABLE	0x02
 
 #define C_LNK_NEGOTIATION	0x0b
+#define C_C_NEGOTIATE_BOTH	0x00
+#define C_C_NEGOTIATE_GIG	0x01
+#define C_C_NEGOTIATE_10_100	0x02
+
 #define C_SET_MAC_ADDR		0x0c
 #define C_CLEAR_PROFILE		0x0d
 
@@ -429,33 +435,30 @@
 
 
 /*
- * Descriptor types.
+ * Descriptor flags
  */
+#define BD_FLG_TCP_UDP_SUM	0x01
+#define BD_FLG_IP_SUM		0x02
+#define BD_FLG_END		0x04
+#define BD_FLG_JUMBO		0x10
+#define BD_FLG_MINI		0x1000
 
-#define DESC_TX			0x01
-#define DESC_RX			0x02
-#define DESC_END		0x04
-#define DESC_MORE		0x08
 
 /*
- * Control block flags
- */
+ * Ring Control block flags
+ */
+#define RCB_FLG_TCP_UDP_SUM	0x01
+#define RCB_FLG_IP_SUM		0x02
+#define RCB_FLG_VLAN_ASSIST	0x10
+#define RCB_FLG_COAL_INT_ONLY	0x20
+#define RCB_FLG_IEEE_SNAP_SUM	0x80
+#define RCB_FLG_EXT_RX_BD	0x100
+#define RCB_FLG_RNG_DISABLE	0x200
 
-#define FLG_RX_TCP_UDP_SUM	0x01
-#define FLG_RX_IP_SUM		0x02
-#define FLG_RX_SPLIT_HDRS	0x04
-#define FLG_RX_NO_PSDO_HDR_SUM	0x08
-#define FLG_RNG_DISABLED	0x200
-
-/*
- * Descriptor flags
- */
-#define DFLG_RX_JUMBO		0x10
 
 /*
  * TX ring
  */
-
 #define TX_RING_ENTRIES	128
 #define TX_RING_SIZE	(TX_RING_ENTRIES * sizeof(struct tx_desc))
 #define TX_RING_BASE	0x3800
@@ -471,12 +474,16 @@
 #if __LITTLE_ENDIAN
 	u16	flags;
 	u16	size;
+	u16	vlan;
+	u16	reserved;
 #else
 	u16	size;
 	u16	flags;
+	u16	reserved;
+	u16	vlan;
 #endif
 #endif
-	u32	nic_addr;
+	u32	vlanres;
 };
 
 
@@ -493,9 +500,6 @@
 #define RX_RETURN_RING_SIZE	(RX_MAX_RETURN_RING_ENTRIES * \
 				 sizeof(struct rx_desc))
 
-#define RX_RING_THRESH		64
-#define RX_RING_JUMBO_THRESH	48
-
 struct rx_desc{
 	aceaddr	addr;
 #ifdef __LITTLE_ENDIAN
@@ -520,14 +524,14 @@
 	u16	tcp_udp_csum;
 #endif
 #ifdef __LITTLE_ENDIAN
-	u16	reserved;
+	u16	vlan;
 	u16	err_flags;
 #else
 	u16	err_flags;
-	u16	reserved;
+	u16	vlan;
 #endif
-	u32	nic_addr;
-	u32	pad[1];
+	u32	reserved;
+	u32	opague;
 };
 
 
@@ -598,55 +602,72 @@
 	aceaddr	stats2_ptr;
 };
 
+
 /*
- * Struct private for the AceNIC.
+ * struct ace_skb holding the rings of skb's. This is an awful lot of
+ * pointers, but I don't see any other smart mode to do this in an
+ * efficient manner ;-(
  */
+struct ace_skb
+{
+	struct sk_buff		*tx_skbuff[TX_RING_ENTRIES];
+	struct sk_buff		*rx_std_skbuff[RX_STD_RING_ENTRIES];
+	struct sk_buff		*rx_mini_skbuff[RX_MINI_RING_ENTRIES];
+	struct sk_buff		*rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES];
+};
 
+
+/*
+ * Struct private for the AceNIC.
+ *
+ * Elements are grouped so variables used by the tx handling goes
+ * together, and will go into the same cache lines etc. in order to
+ * avoid cache line contention between the rx and tx handling on SMP.
+ *
+ * Frequently accessed variables are put at the beginning of the
+ * struct to help the compiler generate better/shorter code.
+ */
 struct ace_private
 {
+	struct ace_skb		*skb;
 	struct ace_regs		*regs;		/* register base */
-	volatile __u32		*sgt;
-	struct sk_buff		*pkt_buf;	/* Receive buffer */
-/*
- * The send ring is located in the shared memory window
- */
+	int			version, fw_running, fw_up, link;
+	int			promisc, mcast_all;
+	/*
+	 * The send ring is located in the shared memory window
+	 */
+	struct ace_info		*info;
 	struct tx_desc		*tx_ring;
-	struct rx_desc		rx_std_ring[RX_STD_RING_ENTRIES];
+	u32			tx_prd, tx_full, tx_ret_csm;
+	struct timer_list	timer;
+
+	unsigned long		std_refill_busy
+				__attribute__ ((aligned (L1_CACHE_BYTES)));
+	unsigned long		mini_refill_busy, jumbo_refill_busy;
+	atomic_t		cur_rx_bufs,
+				cur_mini_bufs,
+				cur_jumbo_bufs;
+	u32			rx_std_skbprd, rx_mini_skbprd, rx_jumbo_skbprd;
+	u32			cur_rx;
+	struct tq_struct	immediate;
+	int			bh_pending, jumbo;
+	struct rx_desc		rx_std_ring[RX_STD_RING_ENTRIES]
+				__attribute__ ((aligned (L1_CACHE_BYTES)));
 	struct rx_desc		rx_jumbo_ring[RX_JUMBO_RING_ENTRIES];
-#if 0
 	struct rx_desc		rx_mini_ring[RX_MINI_RING_ENTRIES];
-#endif
 	struct rx_desc		rx_return_ring[RX_RETURN_RING_ENTRIES];
 	struct event		evt_ring[EVT_RING_ENTRIES];
-	struct ace_info		*info;
-	struct sk_buff		*tx_skbuff[TX_RING_ENTRIES];
-	struct sk_buff		*rx_std_skbuff[RX_STD_RING_ENTRIES];
-	struct sk_buff		*rx_jumbo_skbuff[RX_JUMBO_RING_ENTRIES];
-	spinlock_t		lock;
-	struct timer_list	timer;
-	u32			cur_rx, tx_prd;
-	u32			dirty_rx, tx_ret_csm, dirty_event;
-	u32			rx_std_skbprd, rx_jumbo_skbprd;
-	u32			tx_full;
 	volatile u32		evt_prd
 				__attribute__ ((aligned (L1_CACHE_BYTES)));
 	volatile u32		rx_ret_prd
 				__attribute__ ((aligned (L1_CACHE_BYTES)));
 	volatile u32		tx_csm
 				__attribute__ ((aligned (L1_CACHE_BYTES)));
-	struct net_device		*next
-				__attribute__ ((aligned (L1_CACHE_BYTES)));
 	unsigned char		*trace_buf;
-	int			fw_running, fw_up, jumbo, promisc, mcast_all;
-	int			version;
-	int			flags;
-	u16			vendor;
-	u16			pci_command;
 	struct pci_dev		*pdev;
-#if 0
-	u8			pci_bus;
-	u8			pci_dev_fun;
-#endif
+	struct net_device	*next;
+	u16			pci_command;
+	u8			pci_latency;
 	char			name[24];
 	struct net_device_stats stats;
 };
@@ -655,8 +676,9 @@
  * Prototypes
  */
 static int ace_init(struct net_device *dev, int board_idx);
-static int ace_load_std_rx_ring(struct net_device *dev);
-static int ace_load_jumbo_rx_ring(struct net_device *dev);
+static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
+static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
+static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
 static int ace_flush_jumbo_rx_ring(struct net_device *dev);
 static void ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int ace_load_firmware(struct net_device *dev);
@@ -664,9 +686,14 @@
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int ace_close(struct net_device *dev);
 static void ace_timer(unsigned long data);
+static void ace_bh(struct net_device *dev);
 static void ace_dump_trace(struct ace_private *ap);
 static void ace_set_multicast_list(struct net_device *dev);
 static int ace_change_mtu(struct net_device *dev, int new_mtu);
+#ifdef SKB_RECYCLE
+extern int ace_recycle(struct sk_buff *skb);
+#endif
+static int ace_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static int ace_set_mac_addr(struct net_device *dev, void *p);
 static struct net_device_stats *ace_get_stats(struct net_device *dev);
 static u8 read_eeprom_byte(struct ace_regs *regs, unsigned long offset);
diff -u --recursive --new-file v2.3.16/linux/drivers/net/acenic_firmware.h linux/drivers/net/acenic_firmware.h
--- v2.3.16/linux/drivers/net/acenic_firmware.h	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/acenic_firmware.h	Sat Sep  4 13:11:36 1999
@@ -1,18 +1,27 @@
+/*
+ * Declare these here even if Tigon I support is disabled to avoid
+ * the compiler complaining about undefined symbols.
+ */
+#define tigonFwReleaseMajor 0xc
+#define tigonFwReleaseMinor 0x3
+#define tigonFwReleaseFix 0xd
+#define tigonFwStartAddr 0x00004000
+#define tigonFwTextAddr 0x00004000
+#define tigonFwTextLen 0x10920
+#define tigonFwRodataAddr 0x00014920
+#define tigonFwRodataLen 0xaa0
+#define tigonFwDataAddr 0x000153e0
+#define tigonFwDataLen 0x150
+#define tigonFwSbssAddr 0x00015530
+#define tigonFwSbssLen 0x2c
+#define tigonFwBssAddr 0x00015560
+#define tigonFwBssLen 0x2080
+u32 tigonFwText[];
+u32 tigonFwData[];
+u32 tigonFwRodata[];
+
+#ifndef CONFIG_ACENIC_OMIT_TIGON_I
 /* Generated by genfw.c */
-int tigonFwReleaseMajor = 0xc;
-int tigonFwReleaseMinor = 0x3;
-int tigonFwReleaseFix = 0xa;
-u32 tigonFwStartAddr = 0x00004000;
-u32 tigonFwTextAddr = 0x00004000;
-int tigonFwTextLen = 0x10920;
-u32 tigonFwRodataAddr = 0x00014920;
-int tigonFwRodataLen = 0xaa0;
-u32 tigonFwDataAddr = 0x000153e0;
-int tigonFwDataLen = 0x150;
-u32 tigonFwSbssAddr = 0x00015530;
-int tigonFwSbssLen = 0x2c;
-u32 tigonFwBssAddr = 0x00015560;
-int tigonFwBssLen = 0x2080;
 u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x10000003, 
 0x0, 0xd, 0xd, 0x3c1d0001, 
@@ -20,13 +29,13 @@
 0xc00100c, 0x0, 0xd, 0x27bdffd8, 
 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 
 0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, 
-0xafbf0024, 0xc00248c, 0xafb00020, 0xc0023ec, 
+0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8, 
 0x0, 0x3c040001, 0x24844984, 0x24050001, 
 0x2e03021, 0x3821, 0x3c100001, 0x261075e0, 
-0xafb00010, 0xc002407, 0xafbb0014, 0x3c02000f, 
+0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f, 
 0x3442ffff, 0x2021024, 0x362102b, 0x10400009, 
 0x24050003, 0x3c040001, 0x24844990, 0x2003021, 
-0x3603821, 0x3c020010, 0xafa20010, 0xc002407, 
+0x3603821, 0x3c020010, 0xafa20010, 0xc002403, 
 0xafa00014, 0x2021, 0x3405c000, 0x3c010001, 
 0x370821, 0xa02083b0, 0x3c010001, 0x370821, 
 0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3, 
@@ -64,12 +73,12 @@
 0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, 
 0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, 
 0x2484499c, 0x3c050001, 0xafa00010, 0xafa00014, 
-0x8ee704fc, 0x34a5f000, 0xc002407, 0x603021, 
-0x26e40030, 0xc00248c, 0x24050400, 0x27440080, 
-0xc00248c, 0x24050080, 0x26e4777c, 0xc00248c, 
+0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021, 
+0x26e40030, 0xc002488, 0x24050400, 0x27440080, 
+0xc002488, 0x24050080, 0x26e4777c, 0xc002488, 
 0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060, 
 0x8f420260, 0x27450200, 0x24060008, 0xaee20068, 
-0x24020006, 0xc00249e, 0xaee20064, 0x3c023b9a, 
+0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a, 
 0x3442ca00, 0x2021, 0x24030002, 0xaee30074, 
 0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, 
 0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, 
@@ -84,10 +93,10 @@
 0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700, 
 0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00, 
 0xaee204c0, 0x8f420218, 0x30420100, 0x10400005, 
-0x0, 0x3c020001, 0x2442e178, 0x800111d, 
-0x21100, 0x3c020001, 0x2442d36c, 0x21100, 
+0x0, 0x3c020001, 0x2442e168, 0x800111d, 
+0x21100, 0x3c020001, 0x2442d35c, 0x21100, 
 0x21182, 0x3c030800, 0x431025, 0x3c010001, 
-0xac221238, 0x3c020001, 0x2442f690, 0x21100, 
+0xac221238, 0x3c020001, 0x2442f680, 0x21100, 
 0x21182, 0x3c030800, 0x431025, 0x3c010001, 
 0xac221278, 0x8ee20000, 0x34424000, 0x8001238, 
 0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608, 
@@ -121,7 +130,7 @@
 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 
 0xaee90608, 0x3c040001, 0x248449a8, 0xafa00010, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
-0xc002407, 0x34a5f000, 0x8001223, 0x0, 
+0xc002403, 0x34a5f000, 0x8001223, 0x0, 
 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 
 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 
 0x0, 0x8f820124, 0x14c20007, 0x0, 
@@ -146,28 +155,28 @@
 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 
 0x24020001, 0xac820004, 0x14c0001b, 0x0, 
 0x3c040001, 0x248449b0, 0xafa00010, 0xafa00014, 
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 
 0x8001223, 0x8ee201b0, 0x3c040001, 0x248449bc, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
-0xc002407, 0x34a5f005, 0x8ee201ac, 0x24420001, 
+0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, 
 0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, 
 0x248449c8, 0x3405f001, 0x24420001, 0xaee20160, 
 0x8ee20160, 0x3021, 0x3821, 0xafa00010, 
-0xc002407, 0xafa00014, 0x8001238, 0x0, 
-0x3c020001, 0x2442f5b8, 0x21100, 0x21182, 
+0xc002403, 0xafa00014, 0x8001238, 0x0, 
+0x3c020001, 0x2442f5a8, 0x21100, 0x21182, 
 0x431025, 0x3c010001, 0xac221278, 0x96e2045a, 
 0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, 
 0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, 
 0x3c040001, 0x248449d4, 0x24020001, 0xa2e204ec, 
 0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, 
-0x2442a3a0, 0x451024, 0x21082, 0xaee304c8, 
+0x2442a390, 0x451024, 0x21082, 0xaee304c8, 
 0x3c030800, 0x431025, 0x3c010001, 0xac221220, 
-0x3c020001, 0x2442ade4, 0x451024, 0x21082, 
+0x3c020001, 0x2442add4, 0x451024, 0x21082, 
 0x431025, 0x3c010001, 0xac221280, 0x96e6045a, 
-0x3821, 0x24050011, 0xafa00010, 0xc002407, 
+0x3821, 0x24050011, 0xafa00010, 0xc002403, 
 0xafa00014, 0x8001268, 0x0, 0x3c020001, 
-0x2442a9e4, 0x21100, 0x21182, 0x3c030800, 
+0x2442a9d4, 0x21100, 0x21182, 0x3c030800, 
 0x431025, 0x3c010001, 0xac221280, 0x96e2046a, 
 0x30420010, 0x14400009, 0x0, 0x96e2047a, 
 0x30420010, 0x10400112, 0x0, 0x96e2046a, 
@@ -203,7 +212,7 @@
 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 
 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 
 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 
-0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 
 0x800136d, 0x0, 0x8f830120, 0x27623800, 
 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 
 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 
@@ -229,16 +238,16 @@
 0x24020012, 0xac820000, 0x24020001, 0xac820004, 
 0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 
 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 
-0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 
+0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 
 0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, 
 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 
-0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 
 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 
 0x8ee20160, 0x3c040001, 0x248449c8, 0x3405f002, 
 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 
-0x3821, 0xafa00010, 0xc002407, 0xafa00014, 
+0x3821, 0xafa00010, 0xc002403, 0xafa00014, 
 0x96e6047a, 0x96e7046a, 0x3c040001, 0x248449e0, 
-0x24050012, 0xafa00010, 0xc002407, 0xafa00014, 
+0x24050012, 0xafa00010, 0xc002403, 0xafa00014, 
 0xc004500, 0x0, 0xc002318, 0x0, 
 0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, 
 0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8, 
@@ -281,7 +290,7 @@
 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 
 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 
 0x248449a8, 0xafa00010, 0xafa00014, 0x8ee60608, 
-0x8f470228, 0x3c050009, 0xc002407, 0x34a5f000, 
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 
 0x80014a5, 0x0, 0x8f830120, 0x27623800, 
 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 
 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 
@@ -307,10 +316,10 @@
 0x24020012, 0xac820000, 0x24020001, 0xac820004, 
 0x14c0001b, 0x0, 0x3c040001, 0x248449b0, 
 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 
-0x3c050009, 0xc002407, 0x34a5f001, 0x8ee201b0, 
+0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 
 0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, 
 0x3c040001, 0x248449bc, 0xafa00014, 0x8ee60608, 
-0x8f470228, 0x3c050009, 0xc002407, 0x34a5f005, 
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 
 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 
 0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, 
 0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd, 
@@ -322,7 +331,7 @@
 0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178, 
 0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c, 
 0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021, 
-0xaee2726c, 0xc004068, 0x0, 0xc004440, 
+0xaee2726c, 0xc004064, 0x0, 0xc004440, 
 0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008, 
 0x27bd0028, 0x3e00008, 0x0, 0x3e00008, 
 0x0, 0x0, 0x0, 0x2402002c, 
@@ -350,7 +359,7 @@
 0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, 
 0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, 
 0x24844a50, 0xafa00014, 0xafa20010, 0x8f8600b0, 
-0x3c050005, 0xc002407, 0x34a50900, 0x8f82011c, 
+0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c, 
 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 
 0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, 
 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 
@@ -382,7 +391,7 @@
 0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, 
 0xf73821, 0x8ce783d0, 0x3c040001, 0x24844a64, 
 0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, 
-0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002407, 
+0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403, 
 0x34a50900, 0x80015cc, 0x0, 0x8f820104, 
 0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4, 
 0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274, 
@@ -415,7 +424,7 @@
 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 
 0x8ee204e4, 0x3c040001, 0x24844a6c, 0xafa00014, 
 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 
-0xc002407, 0x34a5f006, 0x16000003, 0x24020001, 
+0xc002403, 0x34a5f006, 0x16000003, 0x24020001, 
 0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, 
 0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4, 
 0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c, 
@@ -444,7 +453,7 @@
 0x24020012, 0xac820000, 0x24020001, 0xac820004, 
 0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, 
 0x24844a78, 0xafa00014, 0xafa20010, 0x8ee6724c, 
-0x8f470280, 0x3c050009, 0xc002407, 0x34a5f008, 
+0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, 
 0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, 
 0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, 
 0x0, 0xaee04e24, 0x8f820040, 0x30420001, 
@@ -557,7 +566,7 @@
 0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 
 0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, 
 0x24844a90, 0xafa00010, 0xafa00014, 0x8f860120, 
-0x8f870124, 0x34a5f010, 0xc002407, 0x8021, 
+0x8f870124, 0x34a5f010, 0xc002403, 0x8021, 
 0x800197c, 0x0, 0x3c040001, 0x24844a9c, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, 
@@ -590,7 +599,7 @@
 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 
 0x24020001, 0xac820004, 0x5600000c, 0xaee90608, 
 0x3c040001, 0x24844aa8, 0xafa00010, 0xafa00014, 
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f000, 0x800197c, 0x0, 0x8f830120, 
 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 
 0x27663000, 0x8f820128, 0x10c20004, 0x0, 
@@ -616,11 +625,11 @@
 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 
 0xac820004, 0x5600001d, 0x24100001, 0x3c040001, 
 0x24844ab0, 0xafa00010, 0xafa00014, 0x8ee60608, 
-0x8f470228, 0x3c050009, 0xc002407, 0x34a5f001, 
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001, 
 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, 
 0x8ee201b0, 0x3c040001, 0x24844abc, 0xafa00014, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, 
-0xc002407, 0x0, 0x8ee201ac, 0x8021, 
+0xc002403, 0x0, 0x8ee201ac, 0x8021, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, 
 0x24020001, 0x3c010001, 0x370821, 0xa02083b0, 
 0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, 
@@ -691,12 +700,12 @@
 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 
 0x24020001, 0x10620022, 0x0, 0x3c040001, 
 0x24844a84, 0xafa00010, 0xafa00014, 0x8f860120, 
-0x8f870124, 0x3c050009, 0xc002407, 0x34a5f011, 
+0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, 
 0x8001aad, 0x0, 0x3c040001, 0x24844a90, 
 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 
-0xc002407, 0x34a5f010, 0x8001aad, 0x0, 
+0xc002403, 0x34a5f010, 0x8001aad, 0x0, 
 0x3c040001, 0x24844a9c, 0xafa00014, 0x8ee60608, 
-0x8f470228, 0x3c050009, 0xc002407, 0x34a5f00f, 
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, 
 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 
 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 
 0x8ee204d4, 0x30420001, 0x10400055, 0x0, 
@@ -732,7 +741,7 @@
 0xaf820044, 0x8f820044, 0x34420040, 0xaf820044, 
 0x8ee27b88, 0x24430001, 0x28421389, 0x14400005, 
 0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044, 
-0xaee07b88, 0xc0045c1, 0x0, 0x8fbf0024, 
+0xaee07b88, 0xc0045c2, 0x0, 0x8fbf0024, 
 0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8, 
 0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038, 
 0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, 
@@ -743,14 +752,14 @@
 0x10400004, 0x24020001, 0xaf820064, 0x80022f4, 
 0x0, 0x32c20002, 0x1440000c, 0x3c050003, 
 0x3c040001, 0x24844b34, 0x34a50001, 0x2c03021, 
-0x3821, 0xafa00010, 0xc002407, 0xafa00014, 
+0x3821, 0xafa00010, 0xc002403, 0xafa00014, 
 0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, 
 0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, 
 0x21080, 0x5a1021, 0x8c420300, 0xafa20020, 
 0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, 
 0x8001b80, 0xaf42022c, 0x3c040001, 0x24844b40, 
 0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, 
-0xc002407, 0x34a5f01f, 0x3821, 0x14e00003, 
+0xc002403, 0x34a5f01f, 0x3821, 0x14e00003, 
 0x0, 0x80022ed, 0xaf960064, 0x93a20020, 
 0x2443ffff, 0x2c620011, 0x10400658, 0x31080, 
 0x3c010001, 0x220821, 0x8c224bf8, 0x400008, 
@@ -770,7 +779,7 @@
 0x41cc2, 0x431023, 0x41d02, 0x431021, 
 0x41d42, 0x431023, 0x8001bd0, 0xaee20078, 
 0x3c040001, 0x24844b4c, 0xafa00014, 0x8fa60020, 
-0x3c050003, 0xc002407, 0x34a50004, 0x8ee20110, 
+0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110, 
 0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, 
 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, 
 0x920c0, 0x2e41021, 0x9442727c, 0x30424000, 
@@ -786,7 +795,7 @@
 0x618c0, 0x610c0, 0x571821, 0x8c63737c, 
 0x571021, 0xafa30010, 0x8c427380, 0x3c040001, 
 0x24844b58, 0xafa20014, 0x8f470214, 0x3c050003, 
-0xc002407, 0x34a50013, 0x8001c90, 0x3c020800, 
+0xc002403, 0x34a50013, 0x8001c90, 0x3c020800, 
 0x97440212, 0x771021, 0xa444737e, 0x8f440214, 
 0x771021, 0x2e31821, 0xac447380, 0x34028000, 
 0xa462737c, 0x910c0, 0x2e21021, 0x8001c79, 
@@ -804,7 +813,7 @@
 0x4c10023, 0x618c0, 0x910c0, 0x571821, 
 0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, 
 0x3c040001, 0x24844b64, 0xafa20014, 0x8f470214, 
-0x3c050003, 0xc002407, 0x34a5f017, 0x8001c90, 
+0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90, 
 0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, 
 0x8f430214, 0xb71021, 0xac437780, 0x3c020001, 
 0x571021, 0x8c4283b4, 0x24420001, 0x3c010001, 
@@ -880,12 +889,12 @@
 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 
 0x10620022, 0x0, 0x3c040001, 0x24844b70, 
 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 
-0x3c050009, 0xc002407, 0x34a5f011, 0x8001da0, 
+0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0, 
 0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 
 0x34a5f010, 0x8001da0, 0x0, 0x3c040001, 
 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 
-0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 
+0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, 
 0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, 
 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, 
@@ -901,7 +910,7 @@
 0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, 
 0x571021, 0x8c42727c, 0x3c040001, 0x24844b94, 
 0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, 
-0xc002407, 0x1203021, 0x8001e83, 0x3c020800, 
+0xc002403, 0x1203021, 0x8001e83, 0x3c020800, 
 0xb71021, 0x9443727e, 0x97420212, 0x14620019, 
 0x918c0, 0xb71021, 0x8c437280, 0x8f420214, 
 0x14620014, 0x918c0, 0x2e51021, 0x9447727c, 
@@ -929,7 +938,7 @@
 0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, 
 0x3c040001, 0x24844ba0, 0x3c050003, 0xafa20010, 
 0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, 
-0x1203021, 0xc002407, 0xafa20014, 0x8001e83, 
+0x1203021, 0xc002403, 0xafa20014, 0x8001e83, 
 0x3c020800, 0x2021, 0x428c0, 0xb71021, 
 0x9443777e, 0x97420212, 0x5462002b, 0x24840001, 
 0xb71021, 0x8c437780, 0x8f420214, 0x54620026, 
@@ -937,11 +946,11 @@
 0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4, 
 0x3c020001, 0x571021, 0x8c4283b4, 0x809021, 
 0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784, 
-0x2f02021, 0x2f12821, 0xc002494, 0x24060008, 
+0x2f02021, 0x2f12821, 0xc002490, 0x24060008, 
 0x26310008, 0x3c020001, 0x571021, 0x8c4283b4, 
 0x26520001, 0x242102b, 0x1440fff5, 0x26100008, 
 0x3c040001, 0x972021, 0x8c8483b4, 0x24050008, 
-0x420c0, 0x2484777c, 0xc00248c, 0x2e42021, 
+0x420c0, 0x2484777c, 0xc002488, 0x2e42021, 
 0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf, 
 0x428c0, 0x3c020800, 0x34422000, 0xafa20018, 
 0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff, 
@@ -1005,12 +1014,12 @@
 0x0, 0x316300ff, 0x24020001, 0x10620022, 
 0x0, 0x3c040001, 0x24844b70, 0xafa00010, 
 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 
-0xc002407, 0x34a5f011, 0x8001f93, 0x0, 
+0xc002403, 0x34a5f011, 0x8001f93, 0x0, 
 0x3c040001, 0x24844b7c, 0xafa00014, 0x8f860120, 
-0x8f870124, 0x3c050009, 0xc002407, 0x34a5f010, 
+0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 
 0x8001f93, 0x0, 0x3c040001, 0x24844b88, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
-0xc002407, 0x34a5f00f, 0x8ee201ac, 0x24420001, 
+0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 
 0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, 
 0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001, 
 0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020, 
@@ -1021,7 +1030,7 @@
 0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, 
 0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, 
 0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24844ba8, 
-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 
+0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 
 0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, 
 0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, 
 0x22502, 0x24020001, 0x10820005, 0x24020002, 
@@ -1032,7 +1041,7 @@
 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 
 0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, 
 0x8001fea, 0xaee40108, 0x3c040001, 0x24844bb4, 
-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002407, 
+0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 
 0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, 
 0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, 
 0x21d02, 0x24020001, 0x10620005, 0x24020002, 
@@ -1044,21 +1053,21 @@
 0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, 
 0x3463fff7, 0x431024, 0x8002018, 0xaf820220, 
 0x3c040001, 0x24844bc0, 0xafa00014, 0x8fa60020, 
-0x3c050003, 0xc002407, 0x34a5f00b, 0x8ee20114, 
+0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114, 
 0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, 
-0x27840208, 0x27450200, 0xc00249e, 0x24060008, 
-0x26e40094, 0x27450200, 0xc00249e, 0x24060008, 
+0x27840208, 0x27450200, 0xc00249a, 0x24060008, 
+0x26e40094, 0x27450200, 0xc00249a, 0x24060008, 
 0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, 
 0x8ee20134, 0x8f460248, 0x2021, 0xc004fa8, 
 0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, 
 0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, 
 0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, 
 0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070, 
-0xc00248c, 0x24050400, 0xaef301cc, 0xaef401d0, 
+0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0, 
 0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070, 
 0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, 
 0x27450200, 0x24060008, 0xaee20068, 0x24020006, 
-0xc00249e, 0xaee20064, 0x3c023b9a, 0x3442ca00, 
+0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00, 
 0xaee2006c, 0x240203e8, 0x24040002, 0x24030001, 
 0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, 
 0x30420008, 0x10400004, 0x0, 0xaee30108, 
@@ -1145,22 +1154,22 @@
 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 
 0x10620022, 0x0, 0x3c040001, 0x24844b70, 
 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 
-0x3c050009, 0xc002407, 0x34a5f011, 0x80021c4, 
+0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4, 
 0x0, 0x3c040001, 0x24844b7c, 0xafa00014, 
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 
 0x34a5f010, 0x80021c4, 0x0, 0x3c040001, 
 0x24844b88, 0xafa00014, 0x8ee60608, 0x8f470228, 
-0x3c050009, 0xc002407, 0x34a5f00f, 0x8ee201ac, 
+0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, 
 0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, 
 0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168, 
 0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, 
-0x27450200, 0x24060008, 0xc00249e, 0xaee20068, 
+0x27450200, 0x24060008, 0xc00249a, 0xaee20068, 
 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 
 0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, 
 0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, 
 0x24844bcc, 0xafa00010, 0xafa00014, 0x8fa60020, 
-0x3c050003, 0xc002407, 0x34a5f00f, 0x93a20020, 
+0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020, 
 0x3c030700, 0x34631000, 0x431025, 0xafa20018, 
 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, 
 0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0, 
@@ -1192,7 +1201,7 @@
 0x24020007, 0xac820000, 0x24020001, 0xac820004, 
 0x54e0000c, 0xaee90608, 0x3c040001, 0x24844bd4, 
 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 
-0x3c050009, 0xc002407, 0x34a5f000, 0x80022e0, 
+0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0, 
 0x0, 0x8f830120, 0x27623800, 0x24660020, 
 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 
 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 
@@ -1218,10 +1227,10 @@
 0xac820000, 0x24020001, 0xac820004, 0x14e0001b, 
 0x0, 0x3c040001, 0x24844bdc, 0xafa00010, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
-0xc002407, 0x34a5f001, 0x8ee201b0, 0x24420001, 
+0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 
 0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, 
 0x24844be8, 0xafa00014, 0x8ee60608, 0x8f470228, 
-0x3c050009, 0xc002407, 0x34a5f005, 0x8ee201ac, 
+0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, 
 0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, 
 0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c, 
@@ -1237,7 +1246,7 @@
 0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842, 
 0x25290001, 0x125102b, 0x1440fff0, 0x0, 
 0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8, 
-0x27642800, 0xafbf0010, 0xc00248c, 0x24051000, 
+0x27642800, 0xafbf0010, 0xc002488, 0x24051000, 
 0x24020021, 0xaf800100, 0xaf800104, 0xaf800108, 
 0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120, 
 0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134, 
@@ -1247,32 +1256,31 @@
 0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 
 0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, 
 0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, 
-0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002407, 
+0x8f87011c, 0x3c040001, 0x24844ca0, 0xc002403, 
 0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, 
-0x3c020400, 0x1062002b, 0x43102b, 0x14400008, 
-0x3c022000, 0x3c020100, 0x10620026, 0x3c020200, 
-0x10620013, 0x0, 0x8002376, 0x0, 
-0x1062000a, 0x43102b, 0x1040001e, 0x3c024000, 
-0x1462001c, 0x0, 0x8ee20190, 0x24420001, 
-0xaee20190, 0x8002376, 0x8ee20190, 0x8ee2018c, 
-0x24420001, 0xaee2018c, 0x8002376, 0x8ee2018c, 
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 
-0x8f8200b0, 0x34420001, 0xaf8200b0, 0xaf830104, 
-0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 
-0x8ee201a0, 0x24420001, 0xaee201a0, 0x8002379, 
-0x8ee201a0, 0x8f8200b0, 0x34420001, 0xaf8200b0, 
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 
-0xafbf001c, 0xafb00018, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c050001, 0xafa20014, 0x8f8600a0, 
-0x8f87011c, 0x3c040001, 0x24844cac, 0xc002407, 
-0x34a5f000, 0x8f8300a0, 0x3c027f00, 0x621824, 
-0x3c020400, 0x10620055, 0x8021, 0x43102b, 
-0x14400008, 0x3c042000, 0x3c020100, 0x1062004f, 
-0x3c020200, 0x1062003c, 0x0, 0x80023e4, 
-0x0, 0x10640005, 0x83102b, 0x10400047, 
+0x3c020400, 0x10620029, 0x43102b, 0x14400008, 
+0x3c022000, 0x3c020100, 0x10620024, 0x3c020200, 
+0x10620011, 0x0, 0x8002374, 0x0, 
+0x10620008, 0x3c024000, 0x1462001c, 0x0, 
+0x8ee20190, 0x24420001, 0xaee20190, 0x8002374, 
+0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c, 
+0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002, 
+0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, 
+0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd, 
+0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001, 
+0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0, 
+0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008, 
+0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018, 
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, 
+0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001, 
+0x24844cac, 0xc002403, 0x34a5f000, 0x8f8300a0, 
+0x3c027f00, 0x621824, 0x3c020400, 0x10620053, 
+0x8021, 0x43102b, 0x14400008, 0x3c042000, 
+0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a, 
+0x0, 0x80023e0, 0x0, 0x10640003, 
 0x3c024000, 0x14620045, 0x0, 0x8f8200a0, 
 0x441024, 0x10400006, 0x0, 0x8ee20194, 
-0x24420001, 0xaee20194, 0x80023ad, 0x8ee20194, 
+0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194, 
 0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198, 
 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c, 
 0x30420200, 0x1040001b, 0x0, 0x8f8300a0, 
@@ -1281,18 +1289,18 @@
 0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0, 
 0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124, 
 0x8f820124, 0x27633000, 0x43102b, 0x10400005, 
-0x276237e0, 0xaf820124, 0x80023ce, 0x0, 
+0x276237e0, 0xaf820124, 0x80023ca, 0x0, 
 0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024, 
-0x80023e7, 0xaf82011c, 0x8f82011c, 0x34420002, 
+0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002, 
 0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, 
 0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd, 
 0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001, 
-0xaee2019c, 0x80023e7, 0x8ee2019c, 0x8f8200a0, 
+0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0, 
 0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, 
 0x3e00008, 0x27bd0020, 0x0, 0x3c020001, 
 0x8c425418, 0x27bdffe8, 0xafbf0014, 0x14400012, 
 0xafb00010, 0x3c100001, 0x26105560, 0x2002021, 
-0xc00248c, 0x24052000, 0x26021fe0, 0x3c010001, 
+0xc002488, 0x24052000, 0x26021fe0, 0x3c010001, 
 0xac225534, 0x3c010001, 0xac225530, 0xaf420250, 
 0x24022000, 0xaf500254, 0xaf420258, 0x24020001, 
 0x3c010001, 0xac225418, 0x8fbf0014, 0x8fb00010, 
@@ -1313,8 +1321,8 @@
 0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, 
 0xac620000, 0x3c050001, 0x8ca55534, 0x3c020001, 
 0x8c425400, 0xc09021, 0xe09821, 0x10800006, 
-0xaca20004, 0x24a50008, 0xc002494, 0x24060018, 
-0x8002452, 0x0, 0x24a40008, 0xc00248c, 
+0xaca20004, 0x24a50008, 0xc002490, 0x24060018, 
+0x800244e, 0x0, 0x24a40008, 0xc002488, 
 0x24050018, 0x3c020001, 0x8c425534, 0x3c050001, 
 0x24a55560, 0x2442ffe0, 0x3c010001, 0xac225534, 
 0x45102b, 0x10400005, 0x0, 0x3c020001, 
@@ -1347,13 +1355,13 @@
 0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c, 
 0x8ee3726c, 0x441021, 0x62182b, 0x10600006, 
 0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8, 
-0x80028e5, 0x8ee201b8, 0x10400240, 0x31a20200, 
+0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200, 
 0x1040014d, 0x4821, 0x96e2045a, 0x30420010, 
 0x10400149, 0x0, 0x8f840100, 0x27623000, 
 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 
 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 
 0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001, 
-0xaee201a8, 0x8002530, 0x8ee201a8, 0xac8a0000, 
+0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000, 
 0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e, 
 0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c, 
 0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec, 
@@ -1363,17 +1371,17 @@
 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 
 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, 
-0x0, 0x800251a, 0x0, 0x14a00005, 
+0x0, 0x8002516, 0x0, 0x14a00005, 
 0x0, 0x8f820108, 0x24420020, 0xaf820108, 
 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 
-0xac800000, 0x8002530, 0x0, 0x8ee24e28, 
+0xac800000, 0x800252c, 0x0, 0x8ee24e28, 
 0x24030040, 0x24420001, 0x50430003, 0x1021, 
 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 
 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 
 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 
 0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, 
 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 
-0x80028c2, 0x34a5f114, 0x8ee27264, 0x34843800, 
+0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800, 
 0x3641821, 0x24420010, 0x43102b, 0x14400073, 
 0x0, 0x8ee27264, 0x24480010, 0x3641021, 
 0x102102b, 0x14400002, 0x3c02ffff, 0x1024021, 
@@ -1381,7 +1389,7 @@
 0x50400001, 0x27662800, 0x8f820108, 0x10c20004, 
 0x0, 0x8f820104, 0x14c20007, 0x2563000c, 
 0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, 
-0x80025a4, 0x8ee201a8, 0x2c64000c, 0x1441021, 
+0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021, 
 0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e, 
 0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4, 
 0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025, 
@@ -1392,22 +1400,22 @@
 0x24030040, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, 
 0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, 
-0x0, 0x800258e, 0x0, 0x14a00005, 
+0x0, 0x800258a, 0x0, 0x14a00005, 
 0x0, 0x8f820108, 0x24420020, 0xaf820108, 
 0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, 
-0xac800000, 0x80025a4, 0x0, 0x8ee24e28, 
+0xac800000, 0x80025a0, 0x0, 0x8ee24e28, 
 0x24030040, 0x24420001, 0x50430003, 0x1021, 
 0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, 
 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 
 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 
 0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, 
 0x24844f10, 0x3c050004, 0xafa20014, 0x8ee604e4, 
-0x80028c2, 0x34a5f125, 0x34028100, 0xa5020000, 
-0x9582000e, 0x8002621, 0xa5020002, 0x8f850100, 
+0x80028be, 0x34a5f125, 0x34028100, 0xa5020000, 
+0x9582000e, 0x800261d, 0xa5020002, 0x8f850100, 
 0x27623000, 0x24a60020, 0xc2102b, 0x50400001, 
 0x27662800, 0x8f820108, 0x10c20004, 0x0, 
 0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, 
-0x4821, 0x24420001, 0xaee201a8, 0x8002611, 
+0x4821, 0x24420001, 0xaee201a8, 0x800260d, 
 0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, 
 0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e, 
 0x24020006, 0xaca20018, 0x24630010, 0xaca30008, 
@@ -1419,23 +1427,23 @@
 0x1062001b, 0x24030040, 0x8c820004, 0x24420001, 
 0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, 
 0x10430007, 0x0, 0x8ee24e2c, 0x24420001, 
-0x10a20005, 0x0, 0x80025fb, 0x0, 
+0x10a20005, 0x0, 0x80025f7, 0x0, 
 0x14a00005, 0x0, 0x8f820108, 0x24420020, 
 0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, 
-0x50400013, 0xac800000, 0x8002611, 0x0, 
+0x50400013, 0xac800000, 0x800260d, 0x0, 
 0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, 
 0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, 
 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 
 0x24020005, 0xac820000, 0x24020001, 0xac820004, 
 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, 
 0x3c040001, 0x24844f10, 0x3c050004, 0xafa20014, 
-0x8ee604e4, 0x80028c2, 0x34a5f015, 0x8ee37264, 
+0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264, 
 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, 
-0x8002685, 0x24e70004, 0x8f840100, 0x27623000, 
+0x8002681, 0x24e70004, 0x8f840100, 0x27623000, 
 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 
 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 
 0x14a20007, 0x24020006, 0x8ee201a8, 0x4821, 
-0x24420001, 0xaee201a8, 0x800267b, 0x8ee201a8, 
+0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8, 
 0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e, 
 0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c, 
 0x8ee204c8, 0x3c030002, 0x431025, 0xac820010, 
@@ -1446,16 +1454,16 @@
 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 
 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 
 0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, 
-0x8002665, 0x0, 0x14a00005, 0x0, 
+0x8002661, 0x0, 0x14a00005, 0x0, 
 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 
 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 
-0x800267b, 0x0, 0x8ee24e28, 0x24030040, 
+0x8002677, 0x0, 0x8ee24e28, 0x24030040, 
 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 
 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 
 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 
 0x24020001, 0xac820004, 0x15200009, 0x3c050004, 
 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 
-0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f004, 
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004, 
 0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, 
 0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, 
 0x431021, 0xac44000c, 0x8ee27258, 0xafa20018, 
@@ -1470,34 +1478,34 @@
 0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800, 
 0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, 
 0x14e20007, 0x0, 0x8ee201b4, 0x4821, 
-0x24420001, 0xaee201b4, 0x80026c8, 0x8ee201b4, 
+0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4, 
 0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, 
 0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, 
 0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, 
 0x3c040001, 0x24844f1c, 0xafa20014, 0x8fa60018, 
-0x8fa7001c, 0x3c050004, 0xc002407, 0x34a5f005, 
+0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005, 
 0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, 
-0x80028d7, 0xaee0725c, 0x30430003, 0x24020002, 
+0x80028d3, 0xaee0725c, 0x30430003, 0x24020002, 
 0x10620016, 0x28620003, 0x10400005, 0x24020001, 
-0x10620008, 0x0, 0x8002707, 0x0, 
-0x24020003, 0x10620017, 0x0, 0x8002707, 
+0x10620008, 0x0, 0x8002703, 0x0, 
+0x24020003, 0x10620017, 0x0, 0x8002703, 
 0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, 
 0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, 
-0x8ee200e8, 0x8002707, 0x8ee300ec, 0x8ee200f0, 
+0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0, 
 0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, 
-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002707, 
+0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703, 
 0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, 
 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 
 0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0, 
 0x8ee500e4, 0x401821, 0x1021, 0xa32821, 
 0xa3302b, 0x822021, 0x862021, 0xaee400e0, 
-0xaee500e4, 0x80028d7, 0xaee0725c, 0x30e2ffff, 
+0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff, 
 0x104001c1, 0x31a20200, 0x1040014d, 0x4821, 
 0x96e2045a, 0x30420010, 0x10400149, 0x0, 
 0x8f840100, 0x27623000, 0x24850020, 0xa2102b, 
 0x50400001, 0x27652800, 0x8f820108, 0x10a20004, 
 0x0, 0x8f820104, 0x14a20006, 0x2402000c, 
-0x8ee201a8, 0x24420001, 0xaee201a8, 0x8002772, 
+0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e, 
 0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264, 
 0x24060005, 0xa482000e, 0xac860018, 0xac830008, 
 0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010, 
@@ -1507,17 +1515,17 @@
 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 
 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 
-0x24420001, 0x10a20005, 0x0, 0x800275c, 
+0x24420001, 0x10a20005, 0x0, 0x8002758, 
 0x0, 0x14a00005, 0x0, 0x8f820108, 
 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 
-0x2c420011, 0x50400013, 0xac800000, 0x8002772, 
+0x2c420011, 0x50400013, 0xac800000, 0x800276e, 
 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 
 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 
-0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f014, 
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014, 
 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 
 0x43102b, 0x14400073, 0x0, 0x8ee27264, 
 0x24480010, 0x3641021, 0x102102b, 0x14400002, 
@@ -1525,7 +1533,7 @@
 0x24a60020, 0xc2102b, 0x50400001, 0x27662800, 
 0x8f820108, 0x10c20004, 0x0, 0x8f820104, 
 0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821, 
-0x24420001, 0xaee201a8, 0x80027e6, 0x8ee201a8, 
+0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8, 
 0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, 
 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008, 
 0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8, 
@@ -1536,23 +1544,23 @@
 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 
 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 
-0x24420001, 0x10a20005, 0x0, 0x80027d0, 
+0x24420001, 0x10a20005, 0x0, 0x80027cc, 
 0x0, 0x14a00005, 0x0, 0x8f820108, 
 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 
-0x2c420011, 0x50400013, 0xac800000, 0x80027e6, 
+0x2c420011, 0x50400013, 0xac800000, 0x80027e2, 
 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, 
 0x8ee27264, 0x3c040001, 0x24844f10, 0x3c050004, 
-0xafa20014, 0x8ee604e4, 0x80028c2, 0x34a5f015, 
-0x34028100, 0xa5020000, 0x9582000e, 0x8002863, 
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015, 
+0x34028100, 0xa5020000, 0x9582000e, 0x800285f, 
 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 
 0xc2102b, 0x50400001, 0x27662800, 0x8f820108, 
 0x10c20004, 0x0, 0x8f820104, 0x14c20007, 
 0x2563000c, 0x8ee201a8, 0x4821, 0x24420001, 
-0xaee201a8, 0x8002853, 0x8ee201a8, 0x2c64000c, 
+0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c, 
 0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264, 
 0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018, 
 0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c, 
@@ -1564,23 +1572,23 @@
 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 
 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 
 0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, 
-0x800283d, 0x0, 0x14a00005, 0x0, 
+0x8002839, 0x0, 0x14a00005, 0x0, 
 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 
 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 
-0x8002853, 0x0, 0x8ee24e28, 0x24030040, 
+0x800284f, 0x0, 0x8ee24e28, 0x24030040, 
 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 
 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 
 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 
 0x24020001, 0xac820004, 0x1520000a, 0x34028100, 
 0xafab0010, 0x8ee27264, 0x3c040001, 0x24844f10, 
-0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028c2, 
+0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be, 
 0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, 
-0x9582000e, 0xa462000e, 0x80028c6, 0x24e70004, 
+0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004, 
 0x8f830100, 0x27623000, 0x24640020, 0x82102b, 
 0x50400001, 0x27642800, 0x8f820108, 0x10820004, 
 0x0, 0x8f820104, 0x14820007, 0x24050005, 
 0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, 
-0x80028ba, 0x8ee201a8, 0xac6a0000, 0xac6b0004, 
+0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004, 
 0x8ee27264, 0xa467000e, 0xac650018, 0xac620008, 
 0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010, 
 0xaf840100, 0x92e204ec, 0x14400036, 0x24090001, 
@@ -1589,17 +1597,17 @@
 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 
 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 
-0x24420001, 0x10a20005, 0x0, 0x80028a4, 
+0x24420001, 0x10a20005, 0x0, 0x80028a0, 
 0x0, 0x14a00005, 0x0, 0x8f820108, 
 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 
-0x2c420011, 0x50400013, 0xac800000, 0x80028ba, 
+0x2c420011, 0x50400013, 0xac800000, 0x80028b6, 
 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, 
 0x24844f28, 0xafab0010, 0xafa00014, 0x8ee604e4, 
-0x34a5f017, 0xc002407, 0x30e7ffff, 0x80028e5, 
+0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1, 
 0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, 
 0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, 
 0x34a53800, 0x441021, 0xaee2725c, 0x3651021, 
@@ -1620,14 +1628,14 @@
 0xaee27264, 0x8ee37264, 0x42400, 0x3651021, 
 0x3c010001, 0x370821, 0xac2483dc, 0x62182b, 
 0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff, 
-0x431021, 0xaee27264, 0x8ee27264, 0x800291b, 
+0x431021, 0xaee27264, 0x8ee27264, 0x8002917, 
 0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff, 
 0x44102a, 0x10400015, 0x0, 0x8f8200d8, 
 0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c, 
 0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001, 
 0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a, 
 0x10400006, 0x0, 0x8ee201b8, 0x24420001, 
-0xaee201b8, 0x8002a76, 0x8ee201b8, 0x3c020001, 
+0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001, 
 0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc, 
 0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001, 
 0x571021, 0x8c4283d8, 0x1040002f, 0x5021, 
@@ -1642,11 +1650,11 @@
 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e21821, 0x24020015, 0xac620000, 0x24020001, 
-0x80029c3, 0xac620004, 0x8f840100, 0x27623000, 
+0x80029bf, 0xac620004, 0x8f840100, 0x27623000, 
 0x24850020, 0xa2102b, 0x50400001, 0x27652800, 
 0x8f820108, 0x10a20004, 0x0, 0x8f820104, 
 0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001, 
-0xaee201a8, 0x80029c3, 0x8ee201a8, 0xac880000, 
+0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000, 
 0xac890004, 0x8ee37264, 0xa487000e, 0xac820018, 
 0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c, 
 0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001, 
@@ -1656,16 +1664,16 @@
 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, 
 0x8ee54e28, 0x24420001, 0x10430007, 0x0, 
 0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, 
-0x80029ad, 0x0, 0x14a00005, 0x0, 
+0x80029a9, 0x0, 0x14a00005, 0x0, 
 0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, 
 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 
-0x80029c3, 0x0, 0x8ee24e28, 0x24030040, 
+0x80029bf, 0x0, 0x8ee24e28, 0x24030040, 
 0x24420001, 0x50430003, 0x1021, 0x8ee24e28, 
 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 
 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 
 0x24020001, 0xac820004, 0x1540000a, 0x24020001, 
 0xafa90010, 0x8ee27264, 0x3c040001, 0x24844f10, 
-0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a53, 
+0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f, 
 0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, 
 0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, 
 0x370821, 0xac2083d8, 0x3c010001, 0x370821, 
@@ -1675,12 +1683,12 @@
 0x8ee2726c, 0x8ee47258, 0x651824, 0x431023, 
 0xaee2726c, 0x3661021, 0x82202b, 0x14800004, 
 0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258, 
-0x8ee27258, 0x8002a68, 0xaee27264, 0x10400073, 
+0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073, 
 0x0, 0x8f830100, 0x27623000, 0x24640020, 
 0x82102b, 0x14400002, 0x5021, 0x27642800, 
 0x8f820108, 0x10820004, 0x0, 0x8f820104, 
 0x14820006, 0x24050005, 0x8ee201a8, 0x24420001, 
-0xaee201a8, 0x8002a4a, 0x8ee201a8, 0xac680000, 
+0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000, 
 0xac690004, 0x8ee27264, 0xa467000e, 0xac650018, 
 0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c, 
 0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001, 
@@ -1689,18 +1697,18 @@
 0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, 
 0x24420001, 0x10430007, 0x0, 0x8ee24e2c, 
-0x24420001, 0x10a20005, 0x0, 0x8002a34, 
+0x24420001, 0x10a20005, 0x0, 0x8002a30, 
 0x0, 0x14a00005, 0x0, 0x8f820108, 
 0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, 
-0x2c420011, 0x50400013, 0xac800000, 0x8002a4a, 
+0x2c420011, 0x50400013, 0xac800000, 0x8002a46, 
 0x0, 0x8ee24e28, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e28, 0x24420001, 
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, 
 0x24844f28, 0x3c050004, 0xafa90010, 0xafa00014, 
-0x8ee604e4, 0x34a5f237, 0xc002407, 0x30e7ffff, 
-0x8002a76, 0x0, 0x8ee27264, 0x451021, 
+0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff, 
+0x8002a72, 0x0, 0x8ee27264, 0x451021, 
 0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, 
 0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c, 
 0x3641021, 0x62182b, 0x14600004, 0x3c03ffff, 
@@ -1715,7 +1723,7 @@
 0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c, 
 0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28, 
 0x8c870004, 0x14620007, 0xa03021, 0x8f820108, 
-0x24420020, 0xaf820108, 0x8f820108, 0x8002aa6, 
+0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2, 
 0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e2c, 0x24420001, 
 0x210c0, 0x24424e38, 0x2e22021, 0x8c820004, 
@@ -1729,7 +1737,7 @@
 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 
 0x27663000, 0x8f820128, 0x10c20004, 0x0, 
 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 
-0x8021, 0x24420001, 0xaee201a4, 0x8002b16, 
+0x8021, 0x24420001, 0xaee201a4, 0x8002b12, 
 0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, 
 0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, 
 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 
@@ -1740,38 +1748,38 @@
 0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, 
 0x24420001, 0x10430007, 0x0, 0x8ee24e34, 
-0x24420001, 0x10a20005, 0x0, 0x8002b00, 
+0x24420001, 0x10a20005, 0x0, 0x8002afc, 
 0x0, 0x14a00005, 0x0, 0x8f820128, 
 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 
-0x2c420011, 0x50400013, 0xac800000, 0x8002b16, 
+0x2c420011, 0x50400013, 0xac800000, 0x8002b12, 
 0x0, 0x8ee24e30, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e30, 0x24420001, 
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 
 0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, 
 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 
-0x34a5f006, 0x16000003, 0x24020001, 0x8002b75, 
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
+0x34a5f006, 0x16000003, 0x24020001, 0x8002b71, 
 0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, 
 0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0, 
 0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274, 
 0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184, 
-0x8002b75, 0xaee07274, 0x8ee20504, 0x24030040, 
+0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040, 
 0x24420001, 0x50430003, 0x1021, 0x8ee20504, 
 0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018, 
 0x21080, 0x571021, 0x8c440508, 0x24020003, 
 0x1462000f, 0x0, 0x3c020001, 0x571021, 
 0x904283b1, 0x10400014, 0x0, 0x8ee201d0, 
 0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8, 
-0x641821, 0x306300ff, 0x8002b5d, 0xaee35240, 
+0x641821, 0x306300ff, 0x8002b59, 0xaee35240, 
 0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc, 
 0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10, 
 0x441021, 0xaee201d8, 0x8ee20000, 0x34420040, 
-0x8002b75, 0xaee20000, 0x8ee2014c, 0x3c010001, 
+0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001, 
 0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, 
-0x8002b75, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, 
+0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, 
 0x3c040001, 0x24844f40, 0xafa60014, 0xafa20010, 
-0x8cc60018, 0x3c050008, 0xc002407, 0x34a50910, 
+0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910, 
 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 
 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, 
 0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048, 
@@ -1788,7 +1796,7 @@
 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 
 0x27663000, 0x8f820128, 0x10c20004, 0x0, 
 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 
-0x8021, 0x24420001, 0xaee201a4, 0x8002c02, 
+0x8021, 0x24420001, 0xaee201a4, 0x8002bfe, 
 0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, 
 0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, 
 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 
@@ -1799,10 +1807,10 @@
 0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 
 0x24420001, 0x104c0007, 0x0, 0x8ee24e34, 
-0x24420001, 0x10620005, 0x0, 0x8002bec, 
+0x24420001, 0x10620005, 0x0, 0x8002be8, 
 0x0, 0x14600005, 0x0, 0x8f820128, 
 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 
-0x2c420011, 0x50400013, 0xac800000, 0x8002c02, 
+0x2c420011, 0x50400013, 0xac800000, 0x8002bfe, 
 0x0, 0x8ee24e30, 0x240c0040, 0x24420001, 
 0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, 
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
@@ -1810,8 +1818,8 @@
 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, 
 0x3c040001, 0x24844f34, 0xafa00014, 0xafa20010, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, 
-0xc002407, 0xafab0038, 0x8fab0038, 0x1200030a, 
-0x240c0001, 0x8002f1d, 0x0, 0x966c001c, 
+0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a, 
+0x240c0001, 0x8002f19, 0x0, 0x966c001c, 
 0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024, 
 0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc, 
 0x151900, 0x621021, 0x8c52000c, 0x92e27b98, 
@@ -1821,8 +1829,8 @@
 0x8e63001c, 0x8ee204fc, 0x32100, 0x821021, 
 0x8c42000c, 0x37e1821, 0x24420022, 0x43102b, 
 0x1440000a, 0x24050014, 0x8ee204fc, 0x821021, 
-0x8c44000c, 0xafab0038, 0xc002f79, 0x2484000e, 
-0x8fab0038, 0x8002c56, 0x3050ffff, 0x8ee204fc, 
+0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e, 
+0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc, 
 0x821021, 0x8c42000c, 0x9450000e, 0x94430010, 
 0x94440012, 0x94450014, 0x2038021, 0x2048021, 
 0x2058021, 0x94430016, 0x94440018, 0x9445001a, 
@@ -1833,7 +1841,7 @@
 0xa21021, 0x8c43000c, 0x3202ffff, 0x828021, 
 0x37e1021, 0x24630018, 0x62182b, 0x14600009, 
 0x0, 0x8ee204fc, 0xa21021, 0x8c43000c, 
-0x101027, 0x3c01ffff, 0x230821, 0x8002c73, 
+0x101027, 0x3c01ffff, 0x230821, 0x8002c6f, 
 0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c, 
 0x101027, 0xa4620018, 0x96e2045a, 0x8821, 
 0x30420008, 0x14400063, 0xa021, 0x8e63001c, 
@@ -1851,7 +1859,7 @@
 0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, 
 0xe2102b, 0x50400001, 0xeb3821, 0x94e20000, 
 0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, 
-0x50400001, 0xeb3821, 0x94e20000, 0x8002cd4, 
+0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0, 
 0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c, 
 0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021, 
 0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec, 
@@ -1867,8 +1875,8 @@
 0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c, 
 0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021, 
 0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b, 
-0x14400008, 0xe02021, 0x2405000e, 0xc002f79, 
-0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d0d, 
+0x14400008, 0xe02021, 0x2405000e, 0xc002f75, 
+0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09, 
 0x2028021, 0x94e60000, 0x24e70002, 0x94e50000, 
 0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000, 
 0x24e70002, 0x94e40000, 0x24e70002, 0x2068021, 
@@ -1876,7 +1884,7 @@
 0x94e30002, 0x2048021, 0x2028021, 0x2038021, 
 0x101c02, 0x3202ffff, 0x628021, 0x101c02, 
 0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004, 
-0x3205ffff, 0x96620016, 0x8002d1b, 0x512021, 
+0x3205ffff, 0x96620016, 0x8002d17, 0x512021, 
 0x96620016, 0x542021, 0x41402, 0x3083ffff, 
 0x432021, 0x852023, 0x41402, 0x822021, 
 0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4, 
@@ -1889,11 +1897,11 @@
 0x3082ffff, 0x622021, 0x32c20100, 0x14400004, 
 0x41027, 0x92e27b98, 0x14400002, 0x41027, 
 0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821, 
-0x8002d8e, 0xa4240028, 0x8ee27b9c, 0x12a20008, 
+0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008, 
 0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021, 
 0x41c02, 0x3082ffff, 0x622021, 0x32c20100, 
 0x14400004, 0x41027, 0x92e27b98, 0x14400002, 
-0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8e, 
+0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a, 
 0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4, 
 0x24420032, 0x43102b, 0x14400018, 0x0, 
 0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4, 
@@ -1901,7 +1909,7 @@
 0x41c02, 0x3082ffff, 0x622021, 0x32c20100, 
 0x14400004, 0x41027, 0x92e27b98, 0x14400002, 
 0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 
-0x220821, 0x8002d8e, 0xa4240032, 0x8ee27b9c, 
+0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c, 
 0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032, 
 0x822021, 0x41c02, 0x3082ffff, 0x622021, 
 0x32c20100, 0x14400004, 0x41027, 0x92e27b98, 
@@ -1914,7 +1922,7 @@
 0x37e1021, 0x62102b, 0x50400001, 0x6b1821, 
 0x8c620000, 0xac820000, 0x34028100, 0xa4620000, 
 0x24630002, 0x37e1021, 0x62102b, 0x50400001, 
-0x6b1821, 0x97ac002e, 0x8002db8, 0xa46c0000, 
+0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000, 
 0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e, 
 0xa64c000a, 0xae420000, 0xae440004, 0x9662000e, 
 0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e, 
@@ -1924,55 +1932,55 @@
 0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100, 
 0x8ee27ba8, 0x24430001, 0x210c0, 0x571021, 
 0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac, 
-0xac447bb0, 0x8002ea4, 0xaee0725c, 0x10400072, 
+0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072, 
 0x0, 0x8ee27ba8, 0x24430001, 0x210c0, 
 0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c, 
 0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063, 
 0x4821, 0x5021, 0x8f8200f0, 0x24480008, 
 0x27621800, 0x102102b, 0x50400001, 0x27681000, 
 0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4, 
-0x8021, 0x24420001, 0xaee201b4, 0x8002dfe, 
+0x8021, 0x24420001, 0xaee201b4, 0x8002dfa, 
 0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021, 
 0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004, 
 0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088, 
-0x24420001, 0xaee20088, 0x8002e43, 0x8ee20088, 
+0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088, 
 0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c, 
 0x401821, 0x1021, 0xa32821, 0xa3382b, 
 0x822021, 0x872021, 0x8ee204fc, 0xc93021, 
 0x63100, 0xaee400e0, 0xaee500e4, 0xc23021, 
 0x94c2000a, 0x240c0002, 0x21142, 0x30430003, 
 0x106c0016, 0x28620003, 0x10400005, 0x240c0001, 
-0x106c0008, 0x0, 0x8002e43, 0x0, 
-0x240c0003, 0x106c0017, 0x0, 0x8002e43, 
+0x106c0008, 0x0, 0x8002e3f, 0x0, 
+0x240c0003, 0x106c0017, 0x0, 0x8002e3f, 
 0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, 
 0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, 
-0x8ee200e8, 0x8002e43, 0x8ee300ec, 0x8ee200f0, 
+0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0, 
 0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, 
-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e43, 
+0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f, 
 0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, 
 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 
 0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001, 
 0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98, 
-0x8002ea3, 0xaee07ba8, 0x8f8200f0, 0x24470008, 
+0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008, 
 0x27621800, 0xe2102b, 0x50400001, 0x27671000, 
 0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4, 
-0x8021, 0x24420001, 0xaee201b4, 0x8002e61, 
+0x8021, 0x24420001, 0xaee201b4, 0x8002e5d, 
 0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018, 
 0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, 
 0x16000007, 0x0, 0x8ee20088, 0x24420001, 
-0xaee20088, 0x8ee20088, 0x8002ea4, 0xaee0725c, 
+0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c, 
 0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002, 
 0x401821, 0x1021, 0xa32821, 0xa3302b, 
 0x822021, 0x862021, 0x161142, 0x30430003, 
 0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003, 
 0x10400005, 0x240c0001, 0x106c0008, 0x0, 
-0x8002ea4, 0xaee0725c, 0x240c0003, 0x106c0019, 
-0x0, 0x8002ea4, 0xaee0725c, 0x8ee200e8, 
+0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019, 
+0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8, 
 0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, 
 0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec, 
-0x8002ea4, 0xaee0725c, 0x8ee200f0, 0x8ee300f4, 
+0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4, 
 0x24630001, 0x2c640001, 0x441021, 0xaee200f0, 
-0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea4, 
+0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0, 
 0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001, 
 0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, 
 0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c, 
@@ -1983,7 +1991,7 @@
 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 
 0x0, 0x8f820124, 0x14c20007, 0x0, 
 0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, 
-0x8002f0b, 0x8ee201a4, 0x8ee204e4, 0xac62001c, 
+0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c, 
 0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, 
 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 
 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, 
@@ -1994,22 +2002,22 @@
 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 
 0x8ee34e30, 0x24420001, 0x104c0007, 0x0, 
 0x8ee24e34, 0x24420001, 0x10620005, 0x0, 
-0x8002ef5, 0x0, 0x14600005, 0x0, 
+0x8002ef1, 0x0, 0x14600005, 0x0, 
 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 
 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 
-0x8002f0b, 0x0, 0x8ee24e30, 0x240c0040, 
+0x8002f07, 0x0, 0x8ee24e30, 0x240c0040, 
 0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 
 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, 
 0x8ee204e4, 0x3c040001, 0x24844f34, 0xafa00014, 
 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 
-0x34a5f006, 0xc002407, 0xafab0038, 0x8fab0038, 
-0x16000003, 0x240c0001, 0x8002f60, 0xa2ec04f4, 
+0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038, 
+0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4, 
 0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, 
 0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274, 
 0xaee204f8, 0x8f42023c, 0x10400038, 0x0, 
-0x8ee20184, 0x24420001, 0xaee20184, 0x8002f60, 
+0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c, 
 0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001, 
 0x504c0003, 0x1021, 0x8ee20504, 0x24420001, 
 0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003, 
@@ -2017,10 +2025,10 @@
 0x3c020001, 0x571021, 0x904283b1, 0x10400014, 
 0x0, 0x8ee201d0, 0x8ee35240, 0x441021, 
 0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff, 
-0x8002f53, 0xaee35240, 0x8ee201cc, 0x8ee30e10, 
+0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10, 
 0x441021, 0xaee201cc, 0x8ee201d8, 0x641821, 
 0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8, 
-0x8ee20000, 0x34420040, 0x8002f60, 0xaee20000, 
+0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000, 
 0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, 
 0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108, 
 0x24420020, 0xaf820108, 0x8f820108, 0x8f820108, 
@@ -2049,40 +2057,40 @@
 0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, 
 0xa32821, 0xa3302b, 0x822021, 0x862021, 
 0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4, 
-0x80034d0, 0xaf8700e8, 0x3c020001, 0x571021, 
+0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021, 
 0x904283c0, 0x1040000b, 0x0, 0x3c140001, 
 0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821, 
-0x8e7383c8, 0x3c120001, 0x2579021, 0x8003197, 
+0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193, 
 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007, 
 0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, 
 0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, 
 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 
 0x3c040001, 0x24845050, 0xafa20014, 0x8f8600e0, 
-0x8f8700e4, 0x3c050006, 0xc002407, 0x34a5f000, 
-0x80034d0, 0x0, 0x8fa3001c, 0x8fb20018, 
+0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000, 
+0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018, 
 0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, 
 0x2409821, 0x3c020080, 0x621024, 0x1040000a, 
 0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, 
 0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc, 
-0x80034ca, 0x8ee201fc, 0x3c060004, 0x3c0b0001, 
+0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001, 
 0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, 
 0x3c080020, 0x34078000, 0x24420001, 0xaee20080, 
 0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, 
 0xc3102b, 0x14400007, 0x0, 0x106b0011, 
-0x0, 0x106a0015, 0x0, 0x800304d, 
+0x0, 0x106a0015, 0x0, 0x8003049, 
 0x42042, 0x10650023, 0xa3102b, 0x14400005, 
-0x0, 0x10690019, 0x0, 0x800304d, 
-0x42042, 0x10680021, 0x0, 0x800304d, 
+0x0, 0x10690019, 0x0, 0x8003049, 
+0x42042, 0x10680021, 0x0, 0x8003049, 
 0x42042, 0x8ee20034, 0x24420001, 0xaee20034, 
-0x8ee20034, 0x800304d, 0x42042, 0x8ee201ec, 
-0x24420001, 0xaee201ec, 0x8ee201ec, 0x800304d, 
+0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec, 
+0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049, 
 0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0, 
-0x8ee201f0, 0x800304d, 0x42042, 0x8ee201f4, 
-0x24420001, 0xaee201f4, 0x8ee201f4, 0x800304d, 
+0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4, 
+0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049, 
 0x42042, 0x8ee20030, 0x24420001, 0xaee20030, 
-0x8ee20030, 0x800304d, 0x42042, 0x8ee201f8, 
+0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8, 
 0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042, 
-0x1087047c, 0x0, 0x8003012, 0x0, 
+0x1087047c, 0x0, 0x800300e, 0x0, 
 0x3c020001, 0x571021, 0x904283b2, 0x14400084, 
 0x24020001, 0x3c030001, 0x771821, 0x906383b3, 
 0x1462007f, 0x3c020100, 0x8e430000, 0x621024, 
@@ -2097,7 +2105,7 @@
 0x94437782, 0x96620004, 0x50620008, 0x24070001, 
 0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, 
 0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, 
-0x10400440, 0x0, 0x80030d9, 0x0, 
+0x10400440, 0x0, 0x80030d5, 0x0, 
 0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, 
 0x428c0, 0x2e51021, 0x9442727c, 0x30424000, 
 0x14400434, 0xb71021, 0x9443727e, 0x96620000, 
@@ -2106,14 +2114,14 @@
 0x94437282, 0x96620004, 0x10620035, 0x418c0, 
 0x2e31021, 0x9442727c, 0x30428000, 0x14400421, 
 0x2e31021, 0x944b727c, 0x96670000, 0xb28c0, 
-0xb71021, 0x9442737e, 0x80030bb, 0x3021, 
+0xb71021, 0x9442737e, 0x80030b7, 0x3021, 
 0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, 
 0x944b737c, 0x30638000, 0x14600010, 0xb28c0, 
 0xb71021, 0x9442737e, 0x1447fff5, 0x1602021, 
 0xb71021, 0x94437380, 0x96620002, 0x5462fff1, 
 0x420c0, 0xb71021, 0x94437382, 0x96620004, 
 0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, 
-0x10400400, 0x0, 0x80030d9, 0x0, 
+0x10400400, 0x0, 0x80030d5, 0x0, 
 0x97430202, 0x96420000, 0x146203fa, 0x0, 
 0x97430204, 0x96420002, 0x146203f6, 0x0, 
 0x97430206, 0x96420004, 0x146203f2, 0x0, 
@@ -2130,7 +2138,7 @@
 0x971021, 0x94437782, 0x96620004, 0x50620008, 
 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 
 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 
-0x30e200ff, 0x14400044, 0x240f0003, 0x80034ca, 
+0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6, 
 0x0, 0x2402021, 0xc0022fe, 0x24050006, 
 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 
 0x30424000, 0x144003af, 0xb71021, 0x9443727e, 
@@ -2139,14 +2147,14 @@
 0xb71021, 0x94437282, 0x96620004, 0x10620027, 
 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 
 0x1440039c, 0x2e31021, 0x944b727c, 0x96670000, 
-0xb28c0, 0xb71021, 0x9442737e, 0x8003140, 
+0xb28c0, 0xb71021, 0x9442737e, 0x800313c, 
 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 
 0x2e41021, 0x944b737c, 0x30638000, 0x14600010, 
 0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5, 
 0x1602021, 0xb71021, 0x94437380, 0x96620002, 
 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 
 0x96620004, 0x5462ffec, 0x420c0, 0x24060001, 
-0x30c200ff, 0x1040037b, 0x0, 0x8003153, 
+0x30c200ff, 0x1040037b, 0x0, 0x800314f, 
 0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260, 
 0x54102b, 0x1040003a, 0x0, 0x8f8300e4, 
 0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, 
@@ -2157,12 +2165,12 @@
 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 
 0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 
 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 
-0xc002407, 0x34a5f003, 0x80034d0, 0x0, 
+0xc002403, 0x34a5f003, 0x80034cc, 0x0, 
 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 
 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
-0x3c050006, 0xc002407, 0x34a5f002, 0x8ee201c0, 
+0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0, 
 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 
-0x2403ffbf, 0x431024, 0x8003474, 0xaee20000, 
+0x2403ffbf, 0x431024, 0x8003470, 0xaee20000, 
 0x96e20468, 0x54102b, 0x10400003, 0x0, 
 0x240f0001, 0xa3af0027, 0x12800301, 0x24160007, 
 0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c, 
@@ -2170,7 +2178,7 @@
 0x0, 0x93a20027, 0x10400014, 0x0, 
 0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244, 
 0x8ee65244, 0x8ee35244, 0x21140, 0x24425248, 
-0x2e28021, 0x24630001, 0x80031c3, 0x306b00ff, 
+0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff, 
 0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0, 
 0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, 
 0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18, 
@@ -2193,7 +2201,7 @@
 0x50400001, 0x27693000, 0x8f820128, 0x11220004, 
 0x0, 0x8f820124, 0x15220007, 0x1401821, 
 0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, 
-0x8003250, 0x8ee201a4, 0x8e040000, 0x8e050004, 
+0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004, 
 0x1021, 0xad130008, 0xa507000e, 0xad160018, 
 0xad06001c, 0xa3302b, 0xa32823, 0x822023, 
 0x862023, 0xad040000, 0xad050004, 0x8ee204c0, 
@@ -2204,26 +2212,26 @@
 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 
 0x8ee34e30, 0x24420001, 0x10550007, 0x0, 
 0x8ee24e34, 0x24420001, 0x10620005, 0x0, 
-0x800323d, 0x0, 0x14600005, 0x0, 
+0x8003239, 0x0, 0x14600005, 0x0, 
 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 
 0x8c820004, 0x2c420011, 0x50400010, 0xac800000, 
-0x8003250, 0x0, 0x8ee24e30, 0x24420001, 
+0x800324c, 0x0, 0x8ee24e30, 0x24420001, 
 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, 
 0x3c050006, 0x8e020018, 0x3c040001, 0x24845070, 
 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 
-0x2003021, 0xc002407, 0xafa30014, 0x93a20037, 
+0x2003021, 0xc002403, 0xafa30014, 0x93a20037, 
 0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, 
 0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004, 
-0xae440008, 0x96020016, 0x8003474, 0xa642000e, 
+0xae440008, 0x96020016, 0x8003470, 0xa642000e, 
 0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e, 
 0x28a1023, 0xa602000a, 0x34620004, 0xa602000e, 
 0x8f880120, 0x27623800, 0x25090020, 0x122102b, 
 0x14400002, 0x306affff, 0x27693000, 0x8f820128, 
 0x11220004, 0x0, 0x8f820124, 0x15220007, 
 0x24040020, 0x8ee201a4, 0x8821, 0x24420001, 
-0xaee201a4, 0x80032ce, 0x8ee201a4, 0x8ee5724c, 
+0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c, 
 0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004, 
 0xad100008, 0xad040018, 0x52940, 0xa01821, 
 0x1021, 0xe33821, 0xe3202b, 0xc23021, 
@@ -2235,22 +2243,22 @@
 0x1062001b, 0x0, 0x8c820004, 0x24420001, 
 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 
 0x10550007, 0x0, 0x8ee24e34, 0x24420001, 
-0x10620005, 0x0, 0x80032bb, 0x0, 
+0x10620005, 0x0, 0x80032b7, 0x0, 
 0x14600005, 0x0, 0x8f820128, 0x24420020, 
 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 
-0x50400010, 0xac800000, 0x80032ce, 0x0, 
+0x50400010, 0xac800000, 0x80032ca, 0x0, 
 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 
 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 
 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 
 0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, 
 0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, 
 0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, 
-0x8ee6724c, 0x800343f, 0x34a5f00b, 0x3c010001, 
+0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001, 
 0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, 
 0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, 
 0x24630001, 0x306307ff, 0x26e25244, 0x15a20006, 
 0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, 
-0x80032f3, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, 
+0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, 
 0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073, 
 0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c, 
 0x8f430240, 0x43102b, 0x14400176, 0xa021, 
@@ -2258,7 +2266,7 @@
 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 
 0x0, 0x8f820124, 0x14c20007, 0x0, 
 0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, 
-0x8003353, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 
+0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 
 0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, 
 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 
 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, 
@@ -2268,23 +2276,23 @@
 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 
 0x24420001, 0x10550007, 0x0, 0x8ee24e34, 
-0x24420001, 0x10620005, 0x0, 0x8003340, 
+0x24420001, 0x10620005, 0x0, 0x800333c, 
 0x0, 0x14600005, 0x0, 0x8f820128, 
 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 
-0x2c420011, 0x50400010, 0xac800000, 0x8003353, 
+0x2c420011, 0x50400010, 0xac800000, 0x800334f, 
 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, 
 0x8ee2724c, 0x3c040001, 0x24845088, 0xafa00014, 
 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 
-0x34a5f008, 0xc002407, 0xafae0048, 0x8fae0048, 
+0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048, 
 0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, 
-0xaee20188, 0x80033cc, 0x8ee20188, 0x8f830120, 
+0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120, 
 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 
 0x27663000, 0x8f820128, 0x10c20004, 0x0, 
 0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, 
-0x8821, 0x24420001, 0xaee201a4, 0x80033be, 
+0x8821, 0x24420001, 0xaee201a4, 0x80033ba, 
 0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, 
 0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, 
 0xa462000e, 0x24020011, 0xac620018, 0xac640000, 
@@ -2295,24 +2303,24 @@
 0x1062001b, 0x0, 0x8c820004, 0x24420001, 
 0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, 
 0x10550007, 0x0, 0x8ee24e34, 0x24420001, 
-0x10620005, 0x0, 0x80033ab, 0x0, 
+0x10620005, 0x0, 0x80033a7, 0x0, 
 0x14600005, 0x0, 0x8f820128, 0x24420020, 
 0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, 
-0x50400010, 0xac800000, 0x80033be, 0x0, 
+0x50400010, 0xac800000, 0x80033ba, 0x0, 
 0x8ee24e30, 0x24420001, 0x50550003, 0x1021, 
 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 
 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 
 0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, 
 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 
 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, 
-0xc002407, 0xafae0048, 0x8fae0048, 0x8ee20174, 
-0x24420001, 0xaee20174, 0x8ee20174, 0x8003472, 
+0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174, 
+0x24420001, 0xaee20174, 0x8ee20174, 0x800346e, 
 0xa021, 0x960c000a, 0x183102b, 0x54400001, 
 0x1801821, 0xa603000a, 0x8f880120, 0x27623800, 
 0x25090020, 0x122102b, 0x50400001, 0x27693000, 
 0x8f820128, 0x11220004, 0x0, 0x8f820124, 
 0x15220007, 0x24040020, 0x8ee201a4, 0x8821, 
-0x24420001, 0xaee201a4, 0x8003433, 0x8ee201a4, 
+0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4, 
 0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e, 
 0x24040004, 0xad100008, 0xad040018, 0x52940, 
 0xa01821, 0x1021, 0xe33821, 0xe3202b, 
@@ -2324,21 +2332,21 @@
 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 
 0x24420001, 0x10550007, 0x0, 0x8ee24e34, 
-0x24420001, 0x10620005, 0x0, 0x8003420, 
+0x24420001, 0x10620005, 0x0, 0x800341c, 
 0x0, 0x14600005, 0x0, 0x8f820128, 
 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 
-0x2c420011, 0x50400010, 0xac800000, 0x8003433, 
+0x2c420011, 0x50400010, 0xac800000, 0x800342f, 
 0x0, 0x8ee24e30, 0x24420001, 0x50550003, 
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0xac960000, 0xac9e0004, 0x1620001d, 0x0, 
 0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, 
 0x3c040001, 0x2484507c, 0x3c050006, 0xafa20014, 
-0x8ee6724c, 0x34a5f00d, 0xc002407, 0x2003821, 
+0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821, 
 0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, 
 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, 
 0xae430004, 0xae440008, 0x96020016, 0xa642000e, 
-0x9602000e, 0x3042fdff, 0x8003474, 0xa602000e, 
+0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e, 
 0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8, 
 0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821, 
 0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a, 
@@ -2355,8 +2363,8 @@
 0x24420004, 0x3c010001, 0x370821, 0xac2283cc, 
 0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff, 
 0x14620006, 0x0, 0x8ee201c4, 0x24420001, 
-0xaee201c4, 0x80034d0, 0x8ee201c4, 0x8ee201bc, 
-0x24420001, 0xaee201bc, 0x80034d0, 0x8ee201bc, 
+0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc, 
+0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc, 
 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, 
 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 
 0x822021, 0x862021, 0xaee400c0, 0xaee500c4, 
@@ -2364,9 +2372,9 @@
 0x14400017, 0x24020003, 0x15e20015, 0x0, 
 0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, 
 0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, 
-0x80034ca, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 
+0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 
 0x24630001, 0x2c640001, 0x441021, 0xaee200d8, 
-0xaee300dc, 0x8ee200d8, 0x80034ca, 0x8ee300dc, 
+0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc, 
 0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, 
 0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, 
 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, 
@@ -2387,40 +2395,40 @@
 0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, 
 0x1021, 0xa32821, 0xa3302b, 0x822021, 
 0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, 
-0xaf8700e4, 0x8003854, 0xaf8700e8, 0x3c020001, 
+0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001, 
 0x571021, 0x904283c0, 0x1040000b, 0x0, 
 0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001, 
 0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021, 
-0x80036ec, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 
+0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 
 0x10430007, 0x4821, 0x8f8200e4, 0x24090001, 
 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 
 0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 
 0x8f8200c8, 0x3c040001, 0x24845050, 0xafa20014, 
-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 
-0x34a5f000, 0x8003854, 0x0, 0x8fa3001c, 
+0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, 
+0x34a5f000, 0x8003850, 0x0, 0x8fa3001c, 
 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, 
 0x10400058, 0x2408821, 0x3c020080, 0x621024, 
 0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, 
 0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, 
-0xaee201fc, 0x800384e, 0x8ee201fc, 0x3c060004, 
+0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004, 
 0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, 
 0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, 
 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 
 0x10660021, 0xc3102b, 0x14400007, 0x0, 
 0x106b0011, 0x0, 0x106a0015, 0x0, 
-0x8003596, 0x42042, 0x10650023, 0xa3102b, 
+0x8003592, 0x42042, 0x10650023, 0xa3102b, 
 0x14400005, 0x0, 0x10690019, 0x0, 
-0x8003596, 0x42042, 0x10680021, 0x0, 
-0x8003596, 0x42042, 0x8ee20034, 0x24420001, 
-0xaee20034, 0x8ee20034, 0x8003596, 0x42042, 
+0x8003592, 0x42042, 0x10680021, 0x0, 
+0x8003592, 0x42042, 0x8ee20034, 0x24420001, 
+0xaee20034, 0x8ee20034, 0x8003592, 0x42042, 
 0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, 
-0x8003596, 0x42042, 0x8ee201f0, 0x24420001, 
-0xaee201f0, 0x8ee201f0, 0x8003596, 0x42042, 
+0x8003592, 0x42042, 0x8ee201f0, 0x24420001, 
+0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042, 
 0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, 
-0x8003596, 0x42042, 0x8ee20030, 0x24420001, 
-0xaee20030, 0x8ee20030, 0x8003596, 0x42042, 
+0x8003592, 0x42042, 0x8ee20030, 0x24420001, 
+0xaee20030, 0x8ee20030, 0x8003592, 0x42042, 
 0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, 
-0x42042, 0x108702b7, 0x0, 0x800355b, 
+0x42042, 0x108702b7, 0x0, 0x8003557, 
 0x0, 0x3c020001, 0x571021, 0x904283b2, 
 0x14400084, 0x24020001, 0x3c030001, 0x771821, 
 0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, 
@@ -2435,7 +2443,7 @@
 0x971021, 0x94437782, 0x96220004, 0x50620008, 
 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 
 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 
-0x30e200ff, 0x1040027b, 0x0, 0x8003622, 
+0x30e200ff, 0x1040027b, 0x0, 0x800361e, 
 0x0, 0x2402021, 0xc0022fe, 0x24050006, 
 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 
 0x30424000, 0x1440026f, 0xb71021, 0x9443727e, 
@@ -2444,14 +2452,14 @@
 0xb71021, 0x94437282, 0x96220004, 0x10620035, 
 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 
 0x1440025c, 0x2e31021, 0x9448727c, 0x96270000, 
-0x828c0, 0xb71021, 0x9442737e, 0x8003604, 
+0x828c0, 0xb71021, 0x9442737e, 0x8003600, 
 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 
 0x2e41021, 0x9448737c, 0x30638000, 0x14600010, 
 0x828c0, 0xb71021, 0x9442737e, 0x1447fff5, 
 0x1002021, 0xb71021, 0x94437380, 0x96220002, 
 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 
 0x96220004, 0x5462ffec, 0x420c0, 0x24060001, 
-0x30c200ff, 0x1040023b, 0x0, 0x8003622, 
+0x30c200ff, 0x1040023b, 0x0, 0x800361e, 
 0x0, 0x97430202, 0x96420000, 0x14620235, 
 0x0, 0x97430204, 0x96420002, 0x14620231, 
 0x0, 0x97430206, 0x96420004, 0x1462022d, 
@@ -2469,7 +2477,7 @@
 0x50620008, 0x24070001, 0x3c020001, 0x571021, 
 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 
 0x520c0, 0x30e200ff, 0x14400044, 0x24140003, 
-0x800384e, 0x0, 0x2402021, 0xc0022fe, 
+0x800384a, 0x0, 0x2402021, 0xc0022fe, 
 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 
 0x9442727c, 0x30424000, 0x144001ea, 0xb71021, 
 0x9443727e, 0x96220000, 0x1462000b, 0x418c0, 
@@ -2478,14 +2486,14 @@
 0x10620027, 0x418c0, 0x2e31021, 0x9442727c, 
 0x30428000, 0x144001d7, 0x2e31021, 0x9448727c, 
 0x96270000, 0x828c0, 0xb71021, 0x9442737e, 
-0x8003689, 0x3021, 0x420c0, 0x2e41021, 
+0x8003685, 0x3021, 0x420c0, 0x2e41021, 
 0x9443737c, 0x2e41021, 0x9448737c, 0x30638000, 
 0x14600010, 0x828c0, 0xb71021, 0x9442737e, 
 0x1447fff5, 0x1002021, 0xb71021, 0x94437380, 
 0x96220002, 0x5462fff1, 0x420c0, 0xb71021, 
 0x94437382, 0x96220004, 0x5462ffec, 0x420c0, 
 0x24060001, 0x30c200ff, 0x104001b6, 0x0, 
-0x800369c, 0x24140003, 0x24140001, 0x8f420260, 
+0x8003698, 0x24140003, 0x24140001, 0x8f420260, 
 0x53102b, 0x10400049, 0x0, 0x8f8300e4, 
 0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, 
 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, 
@@ -2495,23 +2503,23 @@
 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 
 0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845058, 
 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 
-0xc002407, 0x34a5f003, 0x8003854, 0x0, 
+0xc002403, 0x34a5f003, 0x8003850, 0x0, 
 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 
 0x24845064, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
-0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 
+0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, 
 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, 
-0x431024, 0x80037fc, 0xaee20000, 0x8ee25240, 
+0x431024, 0x80037f8, 0xaee20000, 0x8ee25240, 
 0xafa20010, 0x8ee25244, 0x3c040001, 0x24845064, 
 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 
-0xc002407, 0x34a5f002, 0x8ee201c0, 0x24420001, 
-0xaee201c0, 0x80037fc, 0x8ee201c0, 0x96e20468, 
+0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, 
+0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468, 
 0x53102b, 0x54400001, 0x3c158000, 0x12600131, 
 0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280, 
 0x24420001, 0x304207ff, 0x10620108, 0x0, 
 0x12a00014, 0x0, 0x8ee35240, 0x8ee25244, 
 0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244, 
 0x21140, 0x24425248, 0x2e28021, 0x24630001, 
-0x8003716, 0x306800ff, 0x92e27248, 0x1440ffc0, 
+0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0, 
 0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0, 
 0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb, 
 0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18, 
@@ -2532,7 +2540,7 @@
 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 
 0x621825, 0x10600013, 0x26220010, 0x182102b, 
 0x1040000e, 0x0, 0x3c07fff5, 0xf13821, 
-0x94e71010, 0x8003762, 0x24e7000e, 0x92220017, 
+0x94e71010, 0x800375e, 0x24e7000e, 0x92220017, 
 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 
 0x621825, 0x50600004, 0xae110018, 0x96270010, 
 0x24e7000e, 0xae110018, 0x3c020001, 0x571021, 
@@ -2541,7 +2549,7 @@
 0xc2102b, 0x50400001, 0x27663000, 0x8f820128, 
 0x10c20004, 0x0, 0x8f820124, 0x14c20007, 
 0x2402000b, 0x8ee201a4, 0x4821, 0x24420001, 
-0xaee201a4, 0x80037c3, 0x8ee201a4, 0x8e040000, 
+0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000, 
 0x8e050004, 0xac620018, 0x1751025, 0x491025, 
 0xac710008, 0xa467000e, 0xac62001c, 0xac640000, 
 0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120, 
@@ -2552,23 +2560,23 @@
 0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30, 
 0x24020040, 0x24630001, 0x10620007, 0x0, 
 0x8ee24e34, 0x24420001, 0x10a20005, 0x0, 
-0x80037ad, 0x0, 0x14a00005, 0x0, 
+0x80037a9, 0x0, 0x14a00005, 0x0, 
 0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, 
 0x8c820004, 0x2c420011, 0x50400013, 0xac800000, 
-0x80037c3, 0x0, 0x8ee24e30, 0x24030040, 
+0x80037bf, 0x0, 0x8ee24e30, 0x24030040, 
 0x24420001, 0x50430003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 
 0x24020001, 0xac820004, 0x15200018, 0x3c050006, 
 0x8e020018, 0x3c040001, 0x24845070, 0xafa20010, 
 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 
-0xc002407, 0xafa30014, 0x32c200ff, 0x1040002b, 
+0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b, 
 0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, 
 0xa642000c, 0xae430000, 0xae440004, 0xae450008, 
-0x96020016, 0x80037fc, 0xa642000e, 0x154d000a, 
+0x96020016, 0x80037f8, 0xa642000e, 0x154d000a, 
 0x0, 0x9602000e, 0xa613000a, 0x34420004, 
 0xa602000e, 0x3c010001, 0x370821, 0xa02083c0, 
-0x80037fa, 0x9821, 0x9604000a, 0x93102b, 
+0x80037f6, 0x9821, 0x9604000a, 0x93102b, 
 0x10400002, 0x2601821, 0x801821, 0x24020001, 
 0xa603000a, 0x3c010001, 0x370821, 0xa02283c0, 
 0x9604000a, 0x2248821, 0x191102b, 0x10400003, 
@@ -2580,8 +2588,8 @@
 0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, 
 0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280, 
 0x24420001, 0x14620006, 0x0, 0x8ee201c4, 
-0x24420001, 0xaee201c4, 0x8003854, 0x8ee201c4, 
-0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003854, 
+0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4, 
+0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850, 
 0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821, 
 0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, 
 0xa3302b, 0x822021, 0x862021, 0x24020002, 
@@ -2589,9 +2597,9 @@
 0x14400017, 0x24020003, 0x16820015, 0x0, 
 0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, 
 0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, 
-0x800384e, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 
+0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 
 0x24630001, 0x2c640001, 0x441021, 0xaee200d8, 
-0xaee300dc, 0x8ee200d8, 0x800384e, 0x8ee300dc, 
+0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc, 
 0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, 
 0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, 
 0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, 
@@ -2612,40 +2620,40 @@
 0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, 
 0x1021, 0xa32821, 0xa3302b, 0x822021, 
 0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, 
-0xaf8700e4, 0x8003c5f, 0xaf8700e8, 0x3c020001, 
+0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001, 
 0x571021, 0x904283c0, 0x1040000b, 0x0, 
 0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001, 
 0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021, 
-0x8003a5d, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 
+0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 
 0x10430007, 0x3821, 0x8f8200e4, 0x24070001, 
 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 
 0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 
 0x8f8200c8, 0x3c040001, 0x24845094, 0xafa20014, 
-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002407, 
-0x34a5f200, 0x8003c5f, 0x0, 0x8fa3001c, 
+0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, 
+0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c, 
 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, 
 0x10400058, 0x2408021, 0x3c020080, 0x621024, 
 0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, 
 0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, 
-0xaee201fc, 0x8003c59, 0x8ee201fc, 0x3c060004, 
+0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004, 
 0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, 
 0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, 
 0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, 
 0x10660021, 0xc3102b, 0x14400007, 0x0, 
 0x106b0011, 0x0, 0x106a0015, 0x0, 
-0x800391a, 0x42042, 0x10650023, 0xa3102b, 
+0x8003916, 0x42042, 0x10650023, 0xa3102b, 
 0x14400005, 0x0, 0x10690019, 0x0, 
-0x800391a, 0x42042, 0x10680021, 0x0, 
-0x800391a, 0x42042, 0x8ee20034, 0x24420001, 
-0xaee20034, 0x8ee20034, 0x800391a, 0x42042, 
+0x8003916, 0x42042, 0x10680021, 0x0, 
+0x8003916, 0x42042, 0x8ee20034, 0x24420001, 
+0xaee20034, 0x8ee20034, 0x8003916, 0x42042, 
 0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, 
-0x800391a, 0x42042, 0x8ee201f0, 0x24420001, 
-0xaee201f0, 0x8ee201f0, 0x800391a, 0x42042, 
+0x8003916, 0x42042, 0x8ee201f0, 0x24420001, 
+0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042, 
 0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, 
-0x800391a, 0x42042, 0x8ee20030, 0x24420001, 
-0xaee20030, 0x8ee20030, 0x800391a, 0x42042, 
+0x8003916, 0x42042, 0x8ee20030, 0x24420001, 
+0xaee20030, 0x8ee20030, 0x8003916, 0x42042, 
 0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, 
-0x42042, 0x1087033e, 0x0, 0x80038df, 
+0x42042, 0x1087033e, 0x0, 0x80038db, 
 0x0, 0x3c020001, 0x571021, 0x904283b2, 
 0x14400084, 0x24020001, 0x3c030001, 0x771821, 
 0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, 
@@ -2660,7 +2668,7 @@
 0x971021, 0x94437782, 0x96020004, 0x50620008, 
 0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, 
 0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, 
-0x30e200ff, 0x10400302, 0x0, 0x80039a6, 
+0x30e200ff, 0x10400302, 0x0, 0x80039a2, 
 0x0, 0x2402021, 0xc0022fe, 0x24050006, 
 0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, 
 0x30424000, 0x144002f6, 0xb71021, 0x9443727e, 
@@ -2669,14 +2677,14 @@
 0xb71021, 0x94437282, 0x96020004, 0x10620035, 
 0x418c0, 0x2e31021, 0x9442727c, 0x30428000, 
 0x144002e3, 0x2e31021, 0x944d727c, 0x96070000, 
-0xd28c0, 0xb71021, 0x9442737e, 0x8003988, 
+0xd28c0, 0xb71021, 0x9442737e, 0x8003984, 
 0x3021, 0x420c0, 0x2e41021, 0x9443737c, 
 0x2e41021, 0x944d737c, 0x30638000, 0x14600010, 
 0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5, 
 0x1a02021, 0xb71021, 0x94437380, 0x96020002, 
 0x5462fff1, 0x420c0, 0xb71021, 0x94437382, 
 0x96020004, 0x5462ffec, 0x420c0, 0x24060001, 
-0x30c200ff, 0x104002c2, 0x0, 0x80039a6, 
+0x30c200ff, 0x104002c2, 0x0, 0x80039a2, 
 0x0, 0x97430202, 0x96420000, 0x146202bc, 
 0x0, 0x97430204, 0x96420002, 0x146202b8, 
 0x0, 0x97430206, 0x96420004, 0x146202b4, 
@@ -2694,7 +2702,7 @@
 0x50620008, 0x24070001, 0x3c020001, 0x571021, 
 0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, 
 0x520c0, 0x30e200ff, 0x14400044, 0x24150003, 
-0x8003c59, 0x0, 0x2402021, 0xc0022fe, 
+0x8003c55, 0x0, 0x2402021, 0xc0022fe, 
 0x24050006, 0x3044001f, 0x428c0, 0x2e51021, 
 0x9442727c, 0x30424000, 0x14400271, 0xb71021, 
 0x9443727e, 0x96020000, 0x1462000b, 0x418c0, 
@@ -2703,14 +2711,14 @@
 0x10620027, 0x418c0, 0x2e31021, 0x9442727c, 
 0x30428000, 0x1440025e, 0x2e31021, 0x944d727c, 
 0x96070000, 0xd28c0, 0xb71021, 0x9442737e, 
-0x8003a0d, 0x3021, 0x420c0, 0x2e41021, 
+0x8003a09, 0x3021, 0x420c0, 0x2e41021, 
 0x9443737c, 0x2e41021, 0x944d737c, 0x30638000, 
 0x14600010, 0xd28c0, 0xb71021, 0x9442737e, 
 0x1447fff5, 0x1a02021, 0xb71021, 0x94437380, 
 0x96020002, 0x5462fff1, 0x420c0, 0xb71021, 
 0x94437382, 0x96020004, 0x5462ffec, 0x420c0, 
 0x24060001, 0x30c200ff, 0x1040023d, 0x0, 
-0x8003a20, 0x24150003, 0x24150001, 0x8f420260, 
+0x8003a1c, 0x24150003, 0x24150001, 0x8f420260, 
 0x53102b, 0x10400036, 0x0, 0x8f8300e4, 
 0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, 
 0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, 
@@ -2720,11 +2728,11 @@
 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 
 0xafa20010, 0x8f8200e4, 0x3c040001, 0x248450a0, 
 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 
-0xc002407, 0x34a5f203, 0x8003c5f, 0x0, 
+0xc002403, 0x34a5f203, 0x8003c5b, 0x0, 
 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 
 0x248450ac, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
-0x3c050006, 0xc002407, 0x34a5f202, 0x8ee201c0, 
-0x24420001, 0xaee201c0, 0x8003c06, 0x8ee201c0, 
+0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0, 
+0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0, 
 0x96e20468, 0x53102b, 0x54400001, 0x3c168000, 
 0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5, 
 0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280, 
@@ -2732,7 +2740,7 @@
 0x12c00012, 0x0, 0x8ee35240, 0x8ee25244, 
 0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024, 
 0x8ee35244, 0x21140, 0x24425248, 0x2e28821, 
-0x24630001, 0x8003a89, 0x306d00ff, 0x8ee201e0, 
+0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0, 
 0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, 
 0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18, 
 0xb021, 0xafb80024, 0x8ee30e18, 0x21140, 
@@ -2751,7 +2759,7 @@
 0x2418fff8, 0x58c824, 0x6a1821, 0x79102b, 
 0x10400002, 0x3206021, 0x606021, 0x1801821, 
 0x24620007, 0x2418fff8, 0x586024, 0x26c102b, 
-0x14400004, 0x1932823, 0x1832823, 0x8003ac7, 
+0x14400004, 0x1932823, 0x1832823, 0x8003ac3, 
 0xc31021, 0xd31021, 0x4a2023, 0x1c4102b, 
 0x54400001, 0x8f2021, 0x25420040, 0x4c102b, 
 0x14400035, 0x5821, 0x94c3000c, 0x24020800, 
@@ -2761,7 +2769,7 @@
 0x461021, 0x90421017, 0x38430006, 0x2c630001, 
 0x38420011, 0x2c420001, 0x621825, 0x10600014, 
 0x24c20010, 0x1c2102b, 0x1040000e, 0x0, 
-0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af8, 
+0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4, 
 0x2562000e, 0x90c20017, 0x38430006, 0x2c630001, 
 0x38420011, 0x2c420001, 0x621825, 0x10600005, 
 0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821, 
@@ -2774,13 +2782,13 @@
 0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021, 
 0x50a00012, 0x81c02, 0x2ca20002, 0x54400009, 
 0x24a5ffff, 0x94820000, 0x24840002, 0x1024021, 
-0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b25, 
+0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21, 
 0x8f2021, 0x90820000, 0x21200, 0x1024021, 
 0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff, 
 0x624021, 0x3108ffff, 0x1402821, 0x11400011, 
 0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff, 
 0x94820000, 0x24840002, 0x1024021, 0x1c4102b, 
-0x10400006, 0x24a5fffe, 0x8003b3c, 0x8f2021, 
+0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021, 
 0x90820000, 0x21200, 0x1024021, 0x14a0fff2, 
 0x2ca20002, 0x81c02, 0x3102ffff, 0x624021, 
 0x81c02, 0x3102ffff, 0x8f890120, 0x624021, 
@@ -2788,7 +2796,7 @@
 0x3108ffff, 0x27633000, 0x8f820128, 0x10620004, 
 0x0, 0x8f820124, 0x14620007, 0x1402821, 
 0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4, 
-0x8003bcd, 0x8ee201a4, 0x8e260000, 0x8e270004, 
+0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004, 
 0x81400, 0x3448000b, 0xad300008, 0xa52b000e, 
 0xad280018, 0x8fb80044, 0x2021, 0x2961025, 
 0x581025, 0xad22001c, 0xe5102b, 0xe53823, 
@@ -2801,32 +2809,32 @@
 0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0, 
 0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, 
 0x8ee34e30, 0x24420001, 0x105e002a, 0x0, 
-0x8003bac, 0x0, 0x8ee24e30, 0x24420001, 
+0x8003ba8, 0x0, 0x8ee24e30, 0x24420001, 
 0x505e0003, 0x1021, 0x8ee24e30, 0x24420001, 
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
-0x2e22021, 0x8003bca, 0x24020012, 0x8ee24e30, 
+0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30, 
 0x210c0, 0x24425038, 0x2e22021, 0x8c830000, 
 0x24020007, 0x1462001f, 0x0, 0x8ee34e30, 
 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 
 0x24420001, 0x105e0007, 0x0, 0x8ee24e34, 
-0x24420001, 0x10620005, 0x0, 0x8003bb8, 
+0x24420001, 0x10620005, 0x0, 0x8003bb4, 
 0x0, 0x14600005, 0x0, 0x8f820128, 
 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 
-0x2c420011, 0x50400012, 0xac800000, 0x8003bcd, 
+0x2c420011, 0x50400012, 0xac800000, 0x8003bc9, 
 0x0, 0x8ee24e30, 0x24420001, 0x505e0003, 
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020007, 0xac820000, 0x24020001, 0xac820004, 
 0x14e00019, 0x3c050006, 0x3c040001, 0x24845070, 
 0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, 
-0x8e230004, 0x2203021, 0x1603821, 0xc002407, 
+0x8e230004, 0x2203021, 0x1603821, 0xc002403, 
 0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, 
 0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c, 
 0xae430000, 0xae440004, 0xae450008, 0x96220016, 
-0x8003c06, 0xa642000e, 0x1599000a, 0x26a1823, 
+0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823, 
 0x9622000e, 0xa623000a, 0x34420004, 0xa622000e, 
-0x3c010001, 0x370821, 0xa02083c0, 0x8003c03, 
+0x3c010001, 0x370821, 0xa02083c0, 0x8003bff, 
 0x9821, 0x9624000a, 0x83102b, 0x54400001, 
 0x801821, 0x24020001, 0xa623000a, 0x3c010001, 
 0x370821, 0xa02283c0, 0x9622000a, 0x4a1821, 
@@ -2839,18 +2847,18 @@
 0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, 
 0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c, 
 0x14620006, 0x0, 0x8ee201c4, 0x24420001, 
-0xaee201c4, 0x8003c5f, 0x8ee201c4, 0x8ee201bc, 
-0x24420001, 0xaee201bc, 0x8003c5f, 0x8ee201bc, 
+0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc, 
+0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc, 
 0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, 
 0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, 
 0x822021, 0x862021, 0x24020002, 0xaee400c0, 
 0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017, 
 0x24020003, 0x16a20015, 0x0, 0x8ee200d0, 
 0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, 
-0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c59, 
+0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55, 
 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, 
 0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc, 
-0x8ee200d8, 0x8003c59, 0x8ee300dc, 0x8ee200c8, 
+0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8, 
 0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, 
 0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, 
 0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, 
@@ -2861,14 +2869,14 @@
 0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c, 
 0x8ee20e14, 0x622023, 0x4820001, 0x24840200, 
 0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004, 
-0x24020200, 0x8ee30e14, 0x8003c81, 0x431823, 
+0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823, 
 0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff, 
 0x804821, 0x69102a, 0x54400001, 0x604821, 
 0x8f870100, 0x27623000, 0x24e80020, 0x102102b, 
 0x50400001, 0x27682800, 0x8f820108, 0x11020004, 
 0x0, 0x8f820104, 0x15020007, 0x1021, 
 0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8, 
-0x8003cc3, 0x8ee201a8, 0x8ee40e14, 0x42140, 
+0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140, 
 0x801821, 0x8ee40460, 0x8ee50464, 0xa32821, 
 0xa3302b, 0x822021, 0x862021, 0xace40000, 
 0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e, 
@@ -2882,7 +2890,7 @@
 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 
 0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, 
 0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, 
-0x248450b4, 0xc002407, 0x34a5f001, 0x8003ce1, 
+0x248450b4, 0xc002403, 0x34a5f001, 0x8003cdd, 
 0x0, 0x8ee20500, 0x24420001, 0x50430003, 
 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 
 0x8ee20500, 0x21080, 0x571021, 0xac490508, 
@@ -2894,13 +2902,13 @@
 0x0, 0x8ee35238, 0x8ee2523c, 0x622023, 
 0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c, 
 0x43102b, 0x14400004, 0x24020100, 0x8ee3523c, 
-0x8003d03, 0x431823, 0x8ee25244, 0x8ee3523c, 
+0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c, 
 0x431023, 0x2443ffff, 0x804821, 0x69102a, 
 0x54400001, 0x604821, 0x8f870100, 0x27623000, 
 0x24e80020, 0x102102b, 0x50400001, 0x27682800, 
 0x8f820108, 0x11020004, 0x0, 0x8f820104, 
 0x15020007, 0x1021, 0x8ee201a8, 0x2021, 
-0x24420001, 0xaee201a8, 0x8003d45, 0x8ee201a8, 
+0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8, 
 0x8ee4523c, 0x42140, 0x801821, 0x8ee40470, 
 0x8ee50474, 0xa32821, 0xa3302b, 0x822021, 
 0x862021, 0xace40000, 0xace50004, 0x8ee3523c, 
@@ -2914,8 +2922,8 @@
 0x24020003, 0xac620000, 0x24020001, 0xac620004, 
 0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, 
 0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, 
-0x8ee75240, 0x3c040001, 0x248450c0, 0xc002407, 
-0x34a5f010, 0x8003d63, 0x0, 0x8ee20500, 
+0x8ee75240, 0x3c040001, 0x248450c0, 0xc002403, 
+0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500, 
 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 
 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, 
 0x571021, 0xac490508, 0x8ee2523c, 0x491021, 
@@ -2927,7 +2935,7 @@
 0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34, 
 0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0, 
 0x24425038, 0x14830007, 0x2e22821, 0x8f820128, 
-0x24420020, 0xaf820128, 0x8f820128, 0x8003d96, 
+0x24420020, 0xaf820128, 0x8f820128, 0x8003d92, 
 0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001, 
 0x50430003, 0x1021, 0x8ee24e34, 0x24420001, 
 0x210c0, 0x24425038, 0x2e22821, 0x8ca20004, 
@@ -2948,10 +2956,10 @@
 0x95830016, 0x95820018, 0x621823, 0x31402, 
 0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, 
 0x3044ffff, 0x436824, 0x3c030800, 0x431824, 
-0x11a00004, 0xad84001c, 0x41140, 0x8003ddc, 
+0x11a00004, 0xad84001c, 0x41140, 0x8003dd8, 
 0x24425248, 0x41140, 0x24420e20, 0x2e25821, 
 0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e, 
-0x95840016, 0x8003ec4, 0x0, 0x8d690018, 
+0x95840016, 0x8003ec0, 0x0, 0x8d690018, 
 0x4021, 0x952a0000, 0x25290002, 0x95270000, 
 0x25290002, 0x95260000, 0x25290002, 0x95250000, 
 0x25290002, 0x95240000, 0x25290002, 0x95230000, 
@@ -2965,7 +2973,7 @@
 0x721821, 0x94620000, 0x24630002, 0x24a5ffff, 
 0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff, 
 0x622021, 0x41402, 0x3083ffff, 0x431021, 
-0x3042ffff, 0x8003e37, 0x1425021, 0x952a0000, 
+0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000, 
 0x25290002, 0x95280000, 0x25290002, 0x95270000, 
 0x25290002, 0x95260000, 0x25290002, 0x95250000, 
 0x25290002, 0x95230000, 0x25290002, 0x95220000, 
@@ -2982,7 +2990,7 @@
 0x10400034, 0x24690010, 0x229102b, 0x54400001, 
 0x1324821, 0x95250000, 0x24690014, 0x229102b, 
 0x10400002, 0x24a5ffec, 0x1324821, 0x95220000, 
-0x30420fff, 0x14400003, 0x25290002, 0x8003e64, 
+0x30420fff, 0x14400003, 0x25290002, 0x8003e60, 
 0x24130001, 0x9821, 0xa03021, 0x229102b, 
 0x54400001, 0x1324821, 0x91220001, 0x25290002, 
 0xa22821, 0x229102b, 0x54400001, 0x1324821, 
@@ -2991,9 +2999,9 @@
 0x54400001, 0x1324821, 0x95220000, 0x25290002, 
 0xa22821, 0x229102b, 0x54400001, 0x1324821, 
 0x95220000, 0x25290002, 0xa22821, 0x229102b, 
-0x54400001, 0x1324821, 0x95220000, 0x8003e9d, 
+0x54400001, 0x1324821, 0x95220000, 0x8003e99, 
 0xa22821, 0x94650010, 0x94620014, 0x24690016, 
-0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e90, 
+0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c, 
 0x24130001, 0x9821, 0xa03021, 0x91230001, 
 0x25290004, 0x95220000, 0x25290002, 0x95240000, 
 0x25290002, 0xa32821, 0xa22821, 0x95220000, 
@@ -3013,7 +3021,7 @@
 0x122102b, 0x50400001, 0x27693000, 0x8f820128, 
 0x11220004, 0x0, 0x8f820124, 0x15220007, 
 0x24040020, 0x8ee201a4, 0x8021, 0x24420001, 
-0xaee201a4, 0x8003f53, 0x8ee201a4, 0x8ee5724c, 
+0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c, 
 0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e, 
 0xad0a0018, 0x52940, 0xa01821, 0x1021, 
 0xe33821, 0xe3202b, 0xc23021, 0xc43021, 
@@ -3026,41 +3034,41 @@
 0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b, 
 0x0, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b, 
-0x0, 0x8003f32, 0x0, 0x8ee24e30, 
+0x0, 0x8003f2e, 0x0, 0x8ee24e30, 
 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
-0x24425038, 0x2e22021, 0x24020001, 0x8003f52, 
+0x24425038, 0x2e22021, 0x24020001, 0x8003f4e, 
 0xac950000, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, 
 0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, 
 0x0, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, 
 0x0, 0x8ee24e34, 0x24420001, 0x10620005, 
-0x0, 0x8003f3e, 0x0, 0x14600005, 
+0x0, 0x8003f3a, 0x0, 0x14600005, 
 0x0, 0x8f820128, 0x24420020, 0xaf820128, 
 0x8f820128, 0x8c820004, 0x2c420011, 0x50400012, 
-0xac800000, 0x8003f53, 0x0, 0x8ee24e30, 
+0xac800000, 0x8003f4f, 0x0, 0x8ee24e30, 
 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 
 0x24020001, 0xac820004, 0x1600000d, 0x0, 
 0x8f820120, 0x3c040001, 0x24845118, 0xafa00014, 
 0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, 
-0xc002407, 0x34a50001, 0x800405b, 0x0, 
+0xc002403, 0x34a50001, 0x8004057, 0x0, 
 0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, 
 0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, 
-0x8003f6f, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, 
+0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, 
 0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff, 
-0xaee201d8, 0x800405b, 0x8ee201d8, 0x8f420240, 
+0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240, 
 0x104000e5, 0x0, 0x8ee20e1c, 0x24420001, 
-0x800405b, 0xaee20e1c, 0x9582001e, 0xad82001c, 
+0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c, 
 0x8f420240, 0x10400072, 0x0, 0x8ee20e1c, 
 0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b, 
 0x144000d5, 0x0, 0x8f830120, 0x27623800, 
 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 
 0x8f820128, 0x10c20004, 0x0, 0x8f820124, 
 0x14c20007, 0x0, 0x8ee201a4, 0x8021, 
-0x24420001, 0xaee201a4, 0x8003fde, 0x8ee201a4, 
+0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4, 
 0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, 
 0x2462001c, 0xac620008, 0x24020008, 0xa462000e, 
 0x24020011, 0xac620018, 0xac640000, 0xac650004, 
@@ -3071,23 +3079,23 @@
 0x0, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, 
 0x0, 0x8ee24e34, 0x24420001, 0x10620005, 
-0x0, 0x8003fca, 0x0, 0x14600005, 
+0x0, 0x8003fc6, 0x0, 0x14600005, 
 0x0, 0x8f820128, 0x24420020, 0xaf820128, 
 0x8f820128, 0x8c820004, 0x2c420011, 0x50400011, 
-0xac800000, 0x8003fde, 0x0, 0x8ee24e30, 
+0xac800000, 0x8003fda, 0x0, 0x8ee24e30, 
 0x24420001, 0x50540003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 
 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, 
 0x3c040001, 0x24845088, 0xafa00014, 0xafa20010, 
-0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002407, 
+0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403, 
 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, 
-0x24420001, 0xaee20188, 0x8004054, 0x8ee20188, 
+0x24420001, 0xaee20188, 0x8004050, 0x8ee20188, 
 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 
 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 
 0x0, 0x8f820124, 0x14c20007, 0x0, 
 0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, 
-0x8004048, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 
+0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c, 
 0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, 
 0x24020008, 0xa462000e, 0x24020011, 0xac620018, 
 0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, 
@@ -3097,64 +3105,64 @@
 0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, 
 0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, 
 0x24420001, 0x10540007, 0x0, 0x8ee24e34, 
-0x24420001, 0x10620005, 0x0, 0x8004034, 
+0x24420001, 0x10620005, 0x0, 0x8004030, 
 0x0, 0x14600005, 0x0, 0x8f820128, 
 0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, 
-0x2c420011, 0x50400011, 0xac800000, 0x8004048, 
+0x2c420011, 0x50400011, 0xac800000, 0x8004044, 
 0x0, 0x8ee24e30, 0x24420001, 0x50540003, 
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020001, 0xac950000, 0xac820004, 0x1600000b, 
 0x0, 0x8ee2724c, 0x3c040001, 0x24845088, 
 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 
-0x3c050009, 0xc002407, 0x34a5f008, 0x8ee20174, 
-0x24420001, 0xaee20174, 0x800405b, 0x8ee20174, 
+0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174, 
+0x24420001, 0xaee20174, 0x8004057, 0x8ee20174, 
 0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124, 
 0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c, 
 0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 
 0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8, 
 0x27840208, 0x27450200, 0x24060008, 0xafbf0014, 
-0xc00249e, 0xafb00010, 0x2021, 0x24100001, 
+0xc00249a, 0xafb00010, 0x2021, 0x24100001, 
 0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, 
 0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, 
 0x3c010001, 0xac235484, 0x3c010001, 0xac235488, 
 0x3c010001, 0xac20553c, 0x3c010001, 0xac225480, 
 0x3c010001, 0xac235488, 0xc004fa8, 0x24050004, 
-0xc004784, 0x0, 0x8ee20000, 0x3c03feff, 
+0xc004785, 0x0, 0x8ee20000, 0x3c03feff, 
 0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, 
 0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, 
 0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, 
 0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, 
 0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, 
-0x248451d0, 0xc002407, 0x3821, 0x8ee20280, 
+0x248451d0, 0xc002403, 0x3821, 0x8ee20280, 
 0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, 
 0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, 
 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 
 0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214, 
 0x3821, 0x24420001, 0xaee20214, 0x8ee20214, 
 0x3c020300, 0x2021024, 0x10400027, 0x3c110400, 
-0xc00429f, 0x0, 0x3c020100, 0x2021024, 
+0xc00429b, 0x0, 0x3c020100, 0x2021024, 
 0x10400007, 0x0, 0x8ee20218, 0x24420001, 
-0xaee20218, 0x8ee20218, 0x80040ca, 0x3c03fdff, 
+0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff, 
 0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, 
 0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, 
 0x8ee20000, 0x3c040001, 0x248451dc, 0x3c050008, 
 0x2003021, 0x431024, 0xaee20000, 0x8f820220, 
 0x3821, 0x3c030300, 0x481024, 0x431025, 
-0xaf820220, 0xafa00010, 0xc002407, 0xafa00014, 
-0x800429a, 0x0, 0x2111024, 0x1040001f, 
+0xaf820220, 0xafa00010, 0xc002403, 0xafa00014, 
+0x8004296, 0x0, 0x2111024, 0x1040001f, 
 0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, 
 0x3c03fdff, 0x3c040001, 0x248451e8, 0x3c050008, 
 0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, 
-0xc002407, 0x3821, 0x3c03fdff, 0x8ee20000, 
+0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000, 
 0x3463ffff, 0x2002021, 0x431024, 0xc004cf4, 
 0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, 
 0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
-0x431024, 0x8004299, 0x511025, 0x2021024, 
+0x431024, 0x8004295, 0x511025, 0x2021024, 
 0x10400142, 0x0, 0x8ee2022c, 0x24420001, 
 0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff, 
 0x3463ffff, 0x431024, 0x34420004, 0xaf820220, 
-0x8f830054, 0x8f820054, 0x8004112, 0x24630002, 
+0x8f830054, 0x8f820054, 0x800410e, 0x24630002, 
 0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, 
 0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007, 
 0x10400012, 0x0, 0x8f8300e4, 0x2402fff8, 
@@ -3167,7 +3175,7 @@
 0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f, 
 0x3442ffff, 0x24680008, 0x48102b, 0x10400003, 
 0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8, 
-0x8f850120, 0x8f840124, 0x8004149, 0x6021, 
+0x8f850120, 0x8f840124, 0x8004145, 0x6021, 
 0x27623800, 0x82102b, 0x50400001, 0x27643000, 
 0x10a40010, 0x318200ff, 0x8c820018, 0x38430007, 
 0x2c630001, 0x3842000b, 0x2c420001, 0x621825, 
@@ -3177,19 +3185,19 @@
 0x571021, 0x904283c0, 0x14400060, 0x0, 
 0x8f8400e4, 0xc41023, 0x218c3, 0x4620001, 
 0x24630200, 0x8f8900c4, 0x10600005, 0x24020001, 
-0x10620009, 0x0, 0x800418b, 0x0, 
+0x10620009, 0x0, 0x8004187, 0x0, 
 0x8ee20230, 0x1205821, 0x24420001, 0xaee20230, 
-0x80041c0, 0x8ee20230, 0x8ee20234, 0x3c05000a, 
+0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a, 
 0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000, 
 0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001, 
 0x651821, 0x2c62233f, 0x14400040, 0x0, 
 0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8, 
 0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4, 
-0x80041c0, 0x8f8200e4, 0x8ee20238, 0x3c03000a, 
+0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a, 
 0x24420001, 0xaee20238, 0x8c840000, 0x3463f000, 
 0x8ee20238, 0x883823, 0x67102b, 0x54400001, 
 0xe33821, 0x3c020003, 0x34420d40, 0x47102b, 
-0x10400003, 0x0, 0x80041c0, 0x805821, 
+0x10400003, 0x0, 0x80041bc, 0x805821, 
 0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4, 
 0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003, 
 0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c, 
@@ -3197,19 +3205,19 @@
 0x54400001, 0xe53821, 0x147102b, 0x54400007, 
 0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4, 
 0x8f8400e4, 0x1486ffef, 0x0, 0x14860005, 
-0x0, 0x1205821, 0xaf8600e4, 0x80041c0, 
+0x0, 0x1205821, 0xaf8600e4, 0x80041bc, 
 0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8, 
 0x3c03000a, 0x3463f000, 0x483823, 0x67102b, 
 0x54400001, 0xe33821, 0x3c020003, 0x34420d3f, 
 0x47102b, 0x54400007, 0x6021, 0x1683823, 
-0x67102b, 0x54400003, 0xe33821, 0x80041d3, 
+0x67102b, 0x54400003, 0xe33821, 0x80041cf, 
 0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b, 
 0x14400016, 0x318200ff, 0x14400006, 0x0, 
 0x3c020001, 0x571021, 0x904283c0, 0x1040000f, 
 0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000, 
 0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c, 
 0x24020001, 0x641824, 0x3c010001, 0x370821, 
-0xa02283b8, 0x8004230, 0xaee30000, 0xaf8b00c8, 
+0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8, 
 0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000, 
 0x623823, 0x87102b, 0x54400001, 0xe43821, 
 0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001, 
@@ -3228,14 +3236,14 @@
 0x12a4821, 0x10690002, 0x10c1025, 0xac820004, 
 0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220, 
 0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002, 
-0xaf820220, 0x8f830054, 0x8f820054, 0x800423b, 
+0xaf820220, 0x8f830054, 0x8f820054, 0x8004237, 
 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
 0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, 
 0x3463fffb, 0x431024, 0xaf820220, 0x6010055, 
 0x0, 0x8ee20228, 0x24420001, 0xaee20228, 
 0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
 0x431024, 0x34420004, 0xaf820220, 0x8f830054, 
-0x8f820054, 0x8004255, 0x24630002, 0x8f820054, 
+0x8f820054, 0x8004251, 0x24630002, 0x8f820054, 
 0x621023, 0x2c420003, 0x1440fffc, 0x0, 
 0x8f8600e0, 0x30c20007, 0x10400012, 0x0, 
 0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d, 
@@ -3250,7 +3258,7 @@
 0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021, 
 0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002, 
 0x441024, 0x431025, 0xaf820220, 0x8f830054, 
-0x8f820054, 0x8004291, 0x24630001, 0x8f820054, 
+0x8f820054, 0x800428d, 0x24630001, 0x8f820054, 
 0x621023, 0x2c420002, 0x1440fffc, 0x0, 
 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 
 0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
@@ -3259,7 +3267,7 @@
 0x248451f4, 0x3c050008, 0x24020001, 0x3c010001, 
 0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, 
 0x8f860220, 0x34a50498, 0x3c010001, 0xac205498, 
-0x3c010001, 0xac22548c, 0xc002407, 0x3821, 
+0x3c010001, 0xac22548c, 0xc002403, 0x3821, 
 0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, 
 0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, 
 0x431024, 0x30840002, 0x1080011e, 0xaee204d0, 
@@ -3275,7 +3283,7 @@
 0x27623800, 0x24e80020, 0x102102b, 0x50400001, 
 0x27683000, 0x8f820128, 0x11020004, 0x0, 
 0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, 
-0x2821, 0x24420001, 0xaee201a4, 0x8004341, 
+0x2821, 0x24420001, 0xaee201a4, 0x800433d, 
 0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, 
 0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, 
 0x822021, 0x862021, 0xace40000, 0xace50004, 
@@ -3288,10 +3296,10 @@
 0x0, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, 
 0x0, 0x8ee24e34, 0x24420001, 0x10620005, 
-0x0, 0x800432e, 0x0, 0x14600005, 
+0x0, 0x800432a, 0x0, 0x14600005, 
 0x0, 0x8f820128, 0x24420020, 0xaf820128, 
 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 
-0xac800000, 0x8004341, 0x0, 0x8ee24e30, 
+0xac800000, 0x800433d, 0x0, 0x8ee24e30, 
 0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004, 
@@ -3305,7 +3313,7 @@
 0x50400001, 0x27663000, 0x8f820128, 0x10c20004, 
 0x0, 0x8f820124, 0x14c20007, 0x0, 
 0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4, 
-0x80043ad, 0x8ee201a4, 0x8ee20608, 0xac62001c, 
+0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c, 
 0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, 
 0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, 
 0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, 
@@ -3315,30 +3323,30 @@
 0x0, 0x8c820004, 0x24420001, 0xac820004, 
 0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007, 
 0x0, 0x8ee24e34, 0x24420001, 0x10620005, 
-0x0, 0x800439a, 0x0, 0x14600005, 
+0x0, 0x8004396, 0x0, 0x14600005, 
 0x0, 0x8f820128, 0x24420020, 0xaf820128, 
 0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, 
-0xac800000, 0x80043ad, 0x0, 0x8ee24e30, 
+0xac800000, 0x80043a9, 0x0, 0x8ee24e30, 
 0x24420001, 0x50470003, 0x1021, 0x8ee24e30, 
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0xac880000, 0xac8a0004, 
 0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, 
 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 
-0x24020001, 0x54620003, 0xafa00010, 0x80043da, 
+0x24020001, 0x54620003, 0xafa00010, 0x80043d6, 
 0x0, 0x3c040001, 0x24845200, 0xafa00014, 
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002407, 
-0x34a5f011, 0x80043da, 0x0, 0x3c040001, 
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 
+0x34a5f011, 0x80043d6, 0x0, 0x3c040001, 
 0x2484520c, 0xafa00014, 0x8f860120, 0x8f870124, 
-0x3c050009, 0xc002407, 0x34a5f010, 0x80043da, 
+0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6, 
 0x0, 0x3c040001, 0x24845218, 0xafa00014, 
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002407, 
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 
 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 
 0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, 
 0x3c020001, 0x8c425498, 0x27bdffe0, 0x1440000d, 
 0xafbf0018, 0x3c040001, 0x24845224, 0x3c050008, 
 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, 
-0x24020001, 0x3c010001, 0xac225498, 0xc002407, 
+0x24020001, 0x3c010001, 0xac225498, 0xc002403, 
 0x3821, 0x8ee204d0, 0x3c030001, 0x771821, 
 0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, 
 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 
@@ -3358,6 +3366,7 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
+0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x3c120001, 
 0x26521200, 0x3c140001, 0x8e945410, 0x3c100001, 
 0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, 
@@ -3376,19 +3385,19 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x80014d6, 
 0x0, 0x80014d8, 0x3c0a0001, 0x80014d8, 
-0x3c0a0002, 0x80014d8, 0x0, 0x80024aa, 
+0x3c0a0002, 0x80014d8, 0x0, 0x80024a6, 
 0x0, 0x80014d8, 0x3c0a0003, 0x80014d8, 
-0x3c0a0004, 0x8002f90, 0x0, 0x80014d8, 
-0x3c0a0005, 0x8003cec, 0x0, 0x8003c6a, 
+0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8, 
+0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66, 
 0x0, 0x80014d8, 0x3c0a0006, 0x80014d8, 
 0x3c0a0007, 0x80014d8, 0x0, 0x80014d8, 
-0x0, 0x80014d8, 0x0, 0x8002a79, 
+0x0, 0x80014d8, 0x0, 0x8002a75, 
 0x0, 0x80014d8, 0x3c0a000b, 0x80014d8, 
-0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237c, 
+0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a, 
 0x0, 0x8002339, 0x0, 0x80014d8, 
-0x3c0a000e, 0x8001b3c, 0x0, 0x80024a8, 
-0x0, 0x80014d8, 0x3c0a000f, 0x80040ab, 
-0x0, 0x8004095, 0x0, 0x80014d8, 
+0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4, 
+0x0, 0x80014d8, 0x3c0a000f, 0x80040a7, 
+0x0, 0x8004091, 0x0, 0x80014d8, 
 0x3c0a0010, 0x80014ee, 0x0, 0x80014d8, 
 0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8, 
 0x3c0a0013, 0x0, 0x0, 0x0, 
@@ -3436,212 +3445,212 @@
 0x27a60018, 0x8f830054, 0x8f820054, 0x800456f, 
 0x24630064, 0x8f820054, 0x621023, 0x2c420065, 
 0x1440fffc, 0x24040001, 0x24050003, 0xc0048ac, 
-0x27a6001a, 0x97a20020, 0x10400027, 0x24030001, 
+0x27a6001a, 0x97a20020, 0x10400028, 0x24030001, 
 0x3c020001, 0x8c425484, 0x97a30018, 0x34420001, 
-0x3c010001, 0xac225484, 0x24020015, 0x1462000d, 
-0x0, 0x97a2001a, 0x3843f423, 0x2c630001, 
-0x3842f430, 0x2c420001, 0x621825, 0x10600005, 
-0x24020003, 0x3c010001, 0xac225550, 0x80045a7, 
-0x3c08fff0, 0x97a30018, 0x24027810, 0x1462000a, 
-0x24020002, 0x97a3001a, 0x24020001, 0x14620006, 
-0x24020002, 0x24020004, 0x3c010001, 0xac225550, 
-0x80045a7, 0x3c08fff0, 0x3c010001, 0xac225550, 
-0x80045a7, 0x3c08fff0, 0x3c020001, 0x8c425484, 
-0x3c010001, 0xac235550, 0x34420004, 0x3c010001, 
-0xac225484, 0x3c08fff0, 0x3508bdc0, 0x8f830054, 
-0x97a60018, 0x3c070001, 0x8ce75550, 0x3c040001, 
-0x24845290, 0x24020001, 0x3c010001, 0xac22548c, 
-0xafa60010, 0x3c060001, 0x8cc65484, 0x97a2001a, 
-0x3c05000d, 0x34a50100, 0x3c010001, 0xac205488, 
-0x681821, 0x3c010001, 0xac235548, 0xc002407, 
-0xafa20014, 0x8fbf0028, 0x3e00008, 0x27bd0030, 
-0x27bdffe8, 0x24070004, 0x3c040001, 0x8c845488, 
-0x3021, 0x24020001, 0x1482000a, 0xafbf0010, 
-0x3c020001, 0x8c4275cc, 0x3c050004, 0x30428000, 
-0x1040000c, 0x34a593e0, 0x3c05000f, 0x80045da, 
-0x34a54240, 0x3c020001, 0x8c4275cc, 0x3c05000f, 
-0x30428000, 0x10400003, 0x34a54240, 0x3c05001e, 
-0x34a58480, 0x3c020001, 0x8c425548, 0x8f830054, 
-0x451021, 0x431023, 0x45102b, 0x1440002e, 
-0x0, 0x3c020001, 0x8c425490, 0x1440002a, 
-0x2cc20001, 0x7182b, 0x431024, 0x1040001d, 
-0x0, 0x3c090001, 0x8d295484, 0x240b0001, 
-0x3c054000, 0x3c080001, 0x250875cc, 0x250afffc, 
-0x42042, 0x14800002, 0x24e7ffff, 0x24040008, 
-0x891024, 0x5040000b, 0x2cc20001, 0x148b0004, 
-0x0, 0x8d020000, 0x80045ff, 0x451024, 
-0x8d420000, 0x451024, 0x54400001, 0x24060001, 
-0x2cc20001, 0x7182b, 0x431024, 0x5440ffed, 
-0x42042, 0x3c010001, 0x10c00024, 0xac245488, 
-0x8f830054, 0x24020001, 0x3c010001, 0xac22548c, 
-0x3c010001, 0xac235548, 0x3c020001, 0x8c42548c, 
-0x10400006, 0x24020001, 0x3c010001, 0xac20548c, 
-0x3c010001, 0x370821, 0xac2283ac, 0x3c030001, 
-0x771821, 0x8c6383ac, 0x24020008, 0x10620005, 
-0x24020001, 0xc00462f, 0x0, 0x800462c, 
-0x0, 0x3c030001, 0x8c635488, 0x10620007, 
-0x2402000e, 0x3c030001, 0x8c637560, 0x10620003, 
-0x0, 0xc004cf4, 0x8f840220, 0x8fbf0010, 
-0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c02fdff, 
-0xafbf0018, 0x8ee30000, 0x3c050001, 0x8ca55488, 
-0x3c040001, 0x8c8454a8, 0x3442ffff, 0x621824, 
-0x14a40008, 0xaee30000, 0x3c030001, 0x771821, 
-0x8c6383ac, 0x3c020001, 0x8c4254ac, 0x10620008, 
+0x3c010001, 0xac225484, 0x24020015, 0x1462000e, 
+0x0, 0x97a2001a, 0x3042fff0, 0x3843f420, 
+0x2c630001, 0x3842f430, 0x2c420001, 0x621825, 
+0x10600005, 0x24020003, 0x3c010001, 0xac225550, 
+0x80045a8, 0x3c08fff0, 0x97a30018, 0x24027810, 
+0x1462000a, 0x24020002, 0x97a2001a, 0x3042fff0, 
+0x14400006, 0x24020002, 0x24020004, 0x3c010001, 
+0xac225550, 0x80045a8, 0x3c08fff0, 0x3c010001, 
+0xac225550, 0x80045a8, 0x3c08fff0, 0x3c020001, 
+0x8c425484, 0x3c010001, 0xac235550, 0x34420004, 
+0x3c010001, 0xac225484, 0x3c08fff0, 0x3508bdc0, 
+0x8f830054, 0x97a60018, 0x3c070001, 0x8ce75550, 
+0x3c040001, 0x24845290, 0x24020001, 0x3c010001, 
+0xac22548c, 0xafa60010, 0x3c060001, 0x8cc65484, 
+0x97a2001a, 0x3c05000d, 0x34a50100, 0x3c010001, 
+0xac205488, 0x681821, 0x3c010001, 0xac235548, 
+0xc002403, 0xafa20014, 0x8fbf0028, 0x3e00008, 
+0x27bd0030, 0x27bdffe8, 0x24070004, 0x3c040001, 
+0x8c845488, 0x3021, 0x24020001, 0x1482000a, 
+0xafbf0010, 0x3c020001, 0x8c4275cc, 0x3c050004, 
+0x30428000, 0x1040000c, 0x34a593e0, 0x3c05000f, 
+0x80045db, 0x34a54240, 0x3c020001, 0x8c4275cc, 
+0x3c05000f, 0x30428000, 0x10400003, 0x34a54240, 
+0x3c05001e, 0x34a58480, 0x3c020001, 0x8c425548, 
+0x8f830054, 0x451021, 0x431023, 0x45102b, 
+0x1440002e, 0x0, 0x3c020001, 0x8c425490, 
+0x1440002a, 0x2cc20001, 0x7182b, 0x431024, 
+0x1040001d, 0x0, 0x3c090001, 0x8d295484, 
+0x240b0001, 0x3c054000, 0x3c080001, 0x250875cc, 
+0x250afffc, 0x42042, 0x14800002, 0x24e7ffff, 
+0x24040008, 0x891024, 0x5040000b, 0x2cc20001, 
+0x148b0004, 0x0, 0x8d020000, 0x8004600, 
+0x451024, 0x8d420000, 0x451024, 0x54400001, 
+0x24060001, 0x2cc20001, 0x7182b, 0x431024, 
+0x5440ffed, 0x42042, 0x3c010001, 0x10c00024, 
+0xac245488, 0x8f830054, 0x24020001, 0x3c010001, 
+0xac22548c, 0x3c010001, 0xac235548, 0x3c020001, 
+0x8c42548c, 0x10400006, 0x24020001, 0x3c010001, 
+0xac20548c, 0x3c010001, 0x370821, 0xac2283ac, 
+0x3c030001, 0x771821, 0x8c6383ac, 0x24020008, 
+0x10620005, 0x24020001, 0xc004630, 0x0, 
+0x800462d, 0x0, 0x3c030001, 0x8c635488, 
+0x10620007, 0x2402000e, 0x3c030001, 0x8c637560, 
+0x10620003, 0x0, 0xc004cf4, 0x8f840220, 
+0x8fbf0010, 0x3e00008, 0x27bd0018, 0x27bdffe0, 
+0x3c02fdff, 0xafbf0018, 0x8ee30000, 0x3c050001, 
+0x8ca55488, 0x3c040001, 0x8c8454a8, 0x3442ffff, 
+0x621824, 0x14a40008, 0xaee30000, 0x3c030001, 
+0x771821, 0x8c6383ac, 0x3c020001, 0x8c4254ac, 
+0x10620008, 0x0, 0x3c020001, 0x571021, 
+0x8c4283ac, 0x3c010001, 0xac2554a8, 0x3c010001, 
+0xac2254ac, 0x3c030001, 0x8c635488, 0x24020002, 
+0x10620131, 0x2c620003, 0x10400005, 0x24020001, 
+0x10620008, 0x0, 0x800477f, 0x0, 
+0x24020004, 0x10620079, 0x24020001, 0x8004780, 
 0x0, 0x3c020001, 0x571021, 0x8c4283ac, 
-0x3c010001, 0xac2554a8, 0x3c010001, 0xac2254ac, 
-0x3c030001, 0x8c635488, 0x24020002, 0x10620131, 
-0x2c620003, 0x10400005, 0x24020001, 0x10620008, 
-0x0, 0x800477e, 0x0, 0x24020004, 
-0x10620079, 0x24020001, 0x800477f, 0x0, 
-0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 
-0x2c620008, 0x10400122, 0x31080, 0x3c010001, 
-0x220821, 0x8c2252a8, 0x400008, 0x0, 
-0xc004784, 0x0, 0x3c020001, 0x8c425494, 
-0x3c010001, 0xac205420, 0x104000bd, 0x24020002, 
-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, 
-0x8004781, 0xac205494, 0xc00492f, 0x0, 
-0x3c030001, 0x8c6354b0, 0x80046f0, 0x24020011, 
-0x3c050001, 0x8ca55488, 0x3c060001, 0x8cc675cc, 
-0xc004fa8, 0x2021, 0x24020005, 0x3c010001, 
-0xac205494, 0x3c010001, 0x370821, 0x8004781, 
-0xac2283ac, 0x3c040001, 0x2484529c, 0x3c05000f, 
-0x34a50100, 0x3021, 0x3821, 0xafa00010, 
-0xc002407, 0xafa00014, 0x8004781, 0x0, 
-0x8f820220, 0x3c03f700, 0x431025, 0x8004719, 
-0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 
-0x14400090, 0x24020007, 0x8f830054, 0x3c020001, 
+0x2443ffff, 0x2c620008, 0x10400122, 0x31080, 
+0x3c010001, 0x220821, 0x8c2252a8, 0x400008, 
+0x0, 0xc004785, 0x0, 0x3c020001, 
+0x8c425494, 0x3c010001, 0xac205420, 0x104000bd, 
+0x24020002, 0x3c010001, 0x370821, 0xac2283ac, 
+0x3c010001, 0x8004782, 0xac205494, 0xc00492f, 
+0x0, 0x3c030001, 0x8c6354b0, 0x80046f1, 
+0x24020011, 0x3c050001, 0x8ca55488, 0x3c060001, 
+0x8cc675cc, 0xc004fa8, 0x2021, 0x24020005, 
+0x3c010001, 0xac205494, 0x3c010001, 0x370821, 
+0x8004782, 0xac2283ac, 0x3c040001, 0x2484529c, 
+0x3c05000f, 0x34a50100, 0x3021, 0x3821, 
+0xafa00010, 0xc002403, 0xafa00014, 0x8004782, 
+0x0, 0x8f820220, 0x3c03f700, 0x431025, 
+0x800471a, 0xaf820220, 0x8f820220, 0x3c030004, 
+0x431024, 0x14400090, 0x24020007, 0x8f830054, 
+0x3c020001, 0x8c425540, 0x2463d8f0, 0x431023, 
+0x2c422710, 0x144000df, 0x24020001, 0x8004780, 
+0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, 
+0x2021, 0xc00517e, 0x2021, 0x3c030001, 
+0x8c6375c4, 0x46100d1, 0x24020001, 0x3c020008, 
+0x621024, 0x10400006, 0x0, 0x8f820214, 
+0x3c03ffff, 0x431024, 0x80046bd, 0x3442251f, 
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, 
+0xaf820214, 0x8ee20000, 0x3c030200, 0x431025, 
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, 
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 
+0x24020008, 0x3c010001, 0x370821, 0xc0043dd, 
+0xac2283ac, 0x8004782, 0x0, 0x3c020001, 
+0x571021, 0x8c4283ac, 0x2443ffff, 0x2c620008, 
+0x104000ac, 0x31080, 0x3c010001, 0x220821, 
+0x8c2252c8, 0x400008, 0x0, 0xc00429b, 
+0x0, 0x3c010001, 0xac20548c, 0xaf800204, 
+0x3c010001, 0xc004785, 0xac2075b0, 0x24020001, 
+0x3c010001, 0xac2254a0, 0x24020002, 0x3c010001, 
+0x370821, 0x8004782, 0xac2283ac, 0xc004802, 
+0x0, 0x3c030001, 0x8c6354a0, 0x24020009, 
+0x14620090, 0x24020003, 0x3c010001, 0x370821, 
+0x8004782, 0xac2283ac, 0x3c020001, 0x8c4275c8, 
+0x30424000, 0x10400005, 0x0, 0x8f820044, 
+0x3c03ffff, 0x8004702, 0x34637fff, 0x8f820044, 
+0x2403ff7f, 0x431024, 0xaf820044, 0x8f830054, 
+0x800471c, 0x24020004, 0x8f830054, 0x3c020001, 
 0x8c425540, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x144000df, 0x24020001, 0x800477f, 0x0, 
+0x14400074, 0x24020005, 0x3c010001, 0x370821, 
+0x8004782, 0xac2283ac, 0x8f820220, 0x3c03f700, 
+0x431025, 0xaf820220, 0xaf800204, 0x3c010001, 
+0xac2075b0, 0x8f830054, 0x24020006, 0x3c010001, 
+0x370821, 0xac2283ac, 0x3c010001, 0x8004782, 
+0xac235540, 0x8f830054, 0x3c020001, 0x8c425540, 
+0x2463fff6, 0x431023, 0x2c42000a, 0x14400059, 
+0x0, 0x24020007, 0x3c010001, 0x370821, 
+0x8004782, 0xac2283ac, 0x8f820220, 0x3c04f700, 
+0x441025, 0xaf820220, 0x8f820220, 0x3c030300, 
+0x431024, 0x14400005, 0x1821, 0x8f820220, 
+0x24030001, 0x441025, 0xaf820220, 0x10600043, 
+0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, 
+0x8c845538, 0x431024, 0x3442251f, 0xaf820214, 
+0x24020008, 0x3c010001, 0x370821, 0x1080000b, 
+0xac2283ac, 0x3c020001, 0x8c425514, 0x14400007, 
+0x24020001, 0x3c010001, 0xac227560, 0xc004cf4, 
+0x8f840220, 0x800476f, 0x0, 0x8f820220, 
+0x3c030008, 0x431024, 0x14400017, 0x2402000e, 
+0x3c010001, 0xac227560, 0x8ee20000, 0x2021, 
+0x3c030200, 0x431025, 0xc00517e, 0xaee20000, 
+0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 
+0x8f820220, 0x34420002, 0xc0043dd, 0xaf820220, 
 0x3c050001, 0x8ca55488, 0xc0050b3, 0x2021, 
-0xc00517e, 0x2021, 0x3c030001, 0x8c6375c4, 
-0x46100d1, 0x24020001, 0x3c020008, 0x621024, 
-0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 
-0x431024, 0x80046bc, 0x3442251f, 0x8f820214, 
-0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, 
-0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, 
+0x8004782, 0x0, 0x3c020001, 0x8c425514, 
+0x10400010, 0x0, 0x3c020001, 0x8c425510, 
+0x2442ffff, 0x3c010001, 0xac225510, 0x14400009, 
+0x24020002, 0x3c010001, 0xac205514, 0x3c010001, 
+0x8004782, 0xac225510, 0x24020001, 0x3c010001, 
+0xac22548c, 0x8fbf0018, 0x3e00008, 0x27bd0020, 
+0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 
+0xaf820220, 0x8f820200, 0x3c060001, 0x8cc65488, 
+0x34420004, 0xaf820200, 0x24020002, 0x10c2003a, 
+0x2cc20003, 0x10400005, 0x24020001, 0x10c20008, 
+0x0, 0x80047cb, 0x0, 0x24020004, 
+0x10c20013, 0x24020001, 0x80047cb, 0x0, 
+0x3c030001, 0x8c635478, 0x3c020001, 0x8c425480, 
+0x3c040001, 0x8c84549c, 0x3c050001, 0x8ca5547c, 
+0xaf860200, 0xaf860220, 0x34630022, 0x441025, 
+0x451025, 0x34420002, 0x80047ca, 0xaf830200, 
+0x3c030001, 0x8c635538, 0xaf820200, 0x10600009, 
+0xaf820220, 0x3c020001, 0x8c425514, 0x14400005, 
+0x3c033f00, 0x3c020001, 0x8c425470, 0x80047be, 
+0x346300e0, 0x3c020001, 0x8c425470, 0x3c033f00, 
+0x346300e2, 0x431025, 0xaf820200, 0x3c030001, 
+0x8c635474, 0x3c04f700, 0x3c020001, 0x8c425480, 
+0x3c050001, 0x8ca5549c, 0x641825, 0x431025, 
+0x451025, 0xaf820220, 0x3e00008, 0x0, 
+0x8f820220, 0x3c030001, 0x8c635488, 0x34420004, 
+0xaf820220, 0x24020001, 0x1062000f, 0x0, 
+0x8f830054, 0x8f820054, 0x24630002, 0x621023, 
+0x2c420003, 0x10400011, 0x0, 0x8f820054, 
+0x621023, 0x2c420003, 0x1040000c, 0x0, 
+0x80047dc, 0x0, 0x8f830054, 0x8f820054, 
+0x80047e8, 0x24630007, 0x8f820054, 0x621023, 
+0x2c420008, 0x1440fffc, 0x0, 0x8f8400e0, 
+0x30820007, 0x1040000d, 0x0, 0x8f820054, 
+0x8f8300e0, 0x14830009, 0x24450032, 0x8f820054, 
+0xa21023, 0x2c420033, 0x10400004, 0x0, 
+0x8f8200e0, 0x1082fff9, 0x0, 0x8f820220, 
+0x2403fffd, 0x431024, 0xaf820220, 0x3e00008, 
+0x0, 0x3c030001, 0x8c6354a0, 0x3c020001, 
+0x8c4254a4, 0x50620004, 0x2463ffff, 0x3c010001, 
+0xac2354a4, 0x2463ffff, 0x2c620009, 0x1040009d, 
+0x31080, 0x3c010001, 0x220821, 0x8c2252e8, 
+0x400008, 0x0, 0x8f820044, 0x34428080, 
+0xaf820044, 0x8f830054, 0x800489b, 0x24020002, 
+0x8f830054, 0x3c020001, 0x8c425544, 0x2463d8f0, 
+0x431023, 0x2c422710, 0x1440008a, 0x24020003, 
+0x80048a8, 0x0, 0x8f820044, 0x3c03ffff, 
+0x34637fff, 0x431024, 0xaf820044, 0x8f830054, 
+0x800489b, 0x24020004, 0x8f830054, 0x3c020001, 
+0x8c425544, 0x2463fff6, 0x431023, 0x2c42000a, 
+0x14400078, 0x24020005, 0x80048a8, 0x0, 
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 
 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 
-0x8f820220, 0x34420002, 0xaf820220, 0x24020008, 
-0x3c010001, 0x370821, 0xc0043e1, 0xac2283ac, 
-0x8004781, 0x0, 0x3c020001, 0x571021, 
-0x8c4283ac, 0x2443ffff, 0x2c620008, 0x104000ac, 
-0x31080, 0x3c010001, 0x220821, 0x8c2252c8, 
-0x400008, 0x0, 0xc00429f, 0x0, 
-0x3c010001, 0xac20548c, 0xaf800204, 0x3c010001, 
-0xc004784, 0xac2075b0, 0x24020001, 0x3c010001, 
-0xac2254a0, 0x24020002, 0x3c010001, 0x370821, 
-0x8004781, 0xac2283ac, 0xc004801, 0x0, 
-0x3c030001, 0x8c6354a0, 0x24020009, 0x14620090, 
-0x24020003, 0x3c010001, 0x370821, 0x8004781, 
-0xac2283ac, 0x3c020001, 0x8c4275c8, 0x30424000, 
-0x10400005, 0x0, 0x8f820044, 0x3c03ffff, 
-0x8004701, 0x34637fff, 0x8f820044, 0x2403ff7f, 
-0x431024, 0xaf820044, 0x8f830054, 0x800471b, 
-0x24020004, 0x8f830054, 0x3c020001, 0x8c425540, 
-0x2463d8f0, 0x431023, 0x2c422710, 0x14400074, 
-0x24020005, 0x3c010001, 0x370821, 0x8004781, 
-0xac2283ac, 0x8f820220, 0x3c03f700, 0x431025, 
-0xaf820220, 0xaf800204, 0x3c010001, 0xac2075b0, 
-0x8f830054, 0x24020006, 0x3c010001, 0x370821, 
-0xac2283ac, 0x3c010001, 0x8004781, 0xac235540, 
-0x8f830054, 0x3c020001, 0x8c425540, 0x2463fff6, 
-0x431023, 0x2c42000a, 0x14400059, 0x0, 
-0x24020007, 0x3c010001, 0x370821, 0x8004781, 
-0xac2283ac, 0x8f820220, 0x3c04f700, 0x441025, 
-0xaf820220, 0x8f820220, 0x3c030300, 0x431024, 
-0x14400005, 0x1821, 0x8f820220, 0x24030001, 
-0x441025, 0xaf820220, 0x10600043, 0x24020001, 
-0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c845538, 
-0x431024, 0x3442251f, 0xaf820214, 0x24020008, 
-0x3c010001, 0x370821, 0x1080000b, 0xac2283ac, 
-0x3c020001, 0x8c425514, 0x14400007, 0x24020001, 
-0x3c010001, 0xac227560, 0xc004cf4, 0x8f840220, 
-0x800476e, 0x0, 0x8f820220, 0x3c030008, 
-0x431024, 0x14400017, 0x2402000e, 0x3c010001, 
-0xac227560, 0x8ee20000, 0x2021, 0x3c030200, 
-0x431025, 0xc00517e, 0xaee20000, 0x8f820220, 
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
-0x34420002, 0xc0043e1, 0xaf820220, 0x3c050001, 
-0x8ca55488, 0xc0050b3, 0x2021, 0x8004781, 
-0x0, 0x3c020001, 0x8c425514, 0x10400010, 
-0x0, 0x3c020001, 0x8c425510, 0x2442ffff, 
-0x3c010001, 0xac225510, 0x14400009, 0x24020002, 
-0x3c010001, 0xac205514, 0x3c010001, 0x8004781, 
-0xac225510, 0x24020001, 0x3c010001, 0xac22548c, 
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, 
-0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, 
-0x8f820200, 0x3c060001, 0x8cc65488, 0x34420004, 
-0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003, 
-0x10400005, 0x24020001, 0x10c20008, 0x0, 
-0x80047ca, 0x0, 0x24020004, 0x10c20013, 
-0x24020001, 0x80047ca, 0x0, 0x3c030001, 
-0x8c635478, 0x3c020001, 0x8c425480, 0x3c040001, 
-0x8c84549c, 0x3c050001, 0x8ca5547c, 0xaf860200, 
-0xaf860220, 0x34630022, 0x441025, 0x451025, 
-0x34420002, 0x80047c9, 0xaf830200, 0x3c030001, 
-0x8c635538, 0xaf820200, 0x10600009, 0xaf820220, 
-0x3c020001, 0x8c425514, 0x14400005, 0x3c033f00, 
-0x3c020001, 0x8c425470, 0x80047bd, 0x346300e0, 
-0x3c020001, 0x8c425470, 0x3c033f00, 0x346300e2, 
-0x431025, 0xaf820200, 0x3c030001, 0x8c635474, 
-0x3c04f700, 0x3c020001, 0x8c425480, 0x3c050001, 
-0x8ca5549c, 0x641825, 0x431025, 0x451025, 
-0xaf820220, 0x3e00008, 0x0, 0x8f820220, 
-0x3c030001, 0x8c635488, 0x34420004, 0xaf820220, 
-0x24020001, 0x1062000f, 0x0, 0x8f830054, 
-0x8f820054, 0x24630002, 0x621023, 0x2c420003, 
-0x10400011, 0x0, 0x8f820054, 0x621023, 
-0x2c420003, 0x1040000c, 0x0, 0x80047db, 
-0x0, 0x8f830054, 0x8f820054, 0x80047e7, 
-0x24630007, 0x8f820054, 0x621023, 0x2c420008, 
-0x1440fffc, 0x0, 0x8f8400e0, 0x30820007, 
-0x1040000d, 0x0, 0x8f820054, 0x8f8300e0, 
-0x14830009, 0x24450032, 0x8f820054, 0xa21023, 
-0x2c420033, 0x10400004, 0x0, 0x8f8200e0, 
-0x1082fff9, 0x0, 0x8f820220, 0x2403fffd, 
-0x431024, 0xaf820220, 0x3e00008, 0x0, 
-0x3c030001, 0x8c6354a0, 0x3c020001, 0x8c4254a4, 
-0x50620004, 0x2463ffff, 0x3c010001, 0xac2354a4, 
-0x2463ffff, 0x2c620009, 0x1040009d, 0x31080, 
-0x3c010001, 0x220821, 0x8c2252e8, 0x400008, 
-0x0, 0x8f820044, 0x34428080, 0xaf820044, 
-0x8f830054, 0x800489a, 0x24020002, 0x8f830054, 
+0x8f820220, 0x34420002, 0xaf820220, 0x3c023f00, 
+0x344200e0, 0xaf820200, 0x8f820200, 0x2403fffd, 
+0x431024, 0xaf820200, 0x24040001, 0x3405ffff, 
+0xaf840204, 0x8f830054, 0x8f820054, 0x800484f, 
+0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
+0x1440fffc, 0x0, 0x8f820224, 0x42040, 
+0xa4102b, 0x1040fff2, 0x0, 0x8f820220, 
+0x3c03f700, 0x431025, 0xaf820220, 0x8f820214, 
+0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214, 
+0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 
+0x8f820220, 0x3c04f700, 0x34840008, 0x34420002, 
+0xaf820220, 0x8f820220, 0x3c033f00, 0x346300e2, 
+0x441025, 0xaf820220, 0xaf830200, 0x8f8400f0, 
+0x276217f8, 0x14820002, 0x24850008, 0x27651000, 
+0x8f8200f4, 0x10a20007, 0x3c038000, 0x34630040, 
+0x3c020001, 0x24425430, 0xac820000, 0xac830004, 
+0xaf8500f0, 0x8f830054, 0x800489b, 0x24020006, 
+0x8f830054, 0x3c020001, 0x8c425544, 0x2463fff6, 
+0x431023, 0x2c42000a, 0x14400022, 0x24020007, 
+0x80048a8, 0x0, 0x8f8200e0, 0xaf8200e4, 
+0x8f8200e0, 0xaf8200e8, 0x8f820220, 0x34420004, 
+0xaf820220, 0x8f820220, 0x2403fff7, 0x431024, 
+0xaf820220, 0x8f820044, 0x34428080, 0xaf820044, 
+0x8f830054, 0x24020008, 0x3c010001, 0xac2254a0, 
+0x3c010001, 0x80048aa, 0xac235544, 0x8f830054, 
 0x3c020001, 0x8c425544, 0x2463d8f0, 0x431023, 
-0x2c422710, 0x1440008a, 0x24020003, 0x80048a7, 
-0x0, 0x8f820044, 0x3c03ffff, 0x34637fff, 
-0x431024, 0xaf820044, 0x8f830054, 0x800489a, 
-0x24020004, 0x8f830054, 0x3c020001, 0x8c425544, 
-0x2463fff6, 0x431023, 0x2c42000a, 0x14400078, 
-0x24020005, 0x80048a7, 0x0, 0x8f820220, 
-0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, 
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
-0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0, 
-0xaf820200, 0x8f820200, 0x2403fffd, 0x431024, 
-0xaf820200, 0x24040001, 0x3405ffff, 0xaf840204, 
-0x8f830054, 0x8f820054, 0x800484e, 0x24630001, 
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 
-0x0, 0x8f820224, 0x42040, 0xa4102b, 
-0x1040fff2, 0x0, 0x8f820220, 0x3c03f700, 
-0x431025, 0xaf820220, 0x8f820214, 0x3c03ffff, 
-0x431024, 0x3442251f, 0xaf820214, 0x8f820220, 
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
-0x3c04f700, 0x34840008, 0x34420002, 0xaf820220, 
-0x8f820220, 0x3c033f00, 0x346300e2, 0x441025, 
-0xaf820220, 0xaf830200, 0x8f8400f0, 0x276217f8, 
-0x14820002, 0x24850008, 0x27651000, 0x8f8200f4, 
-0x10a20007, 0x3c038000, 0x34630040, 0x3c020001, 
-0x24425430, 0xac820000, 0xac830004, 0xaf8500f0, 
-0x8f830054, 0x800489a, 0x24020006, 0x8f830054, 
-0x3c020001, 0x8c425544, 0x2463fff6, 0x431023, 
-0x2c42000a, 0x14400022, 0x24020007, 0x80048a7, 
-0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0, 
-0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220, 
-0x8f820220, 0x2403fff7, 0x431024, 0xaf820220, 
-0x8f820044, 0x34428080, 0xaf820044, 0x8f830054, 
-0x24020008, 0x3c010001, 0xac2254a0, 0x3c010001, 
-0x80048a9, 0xac235544, 0x8f830054, 0x3c020001, 
-0x8c425544, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400003, 0x24020009, 0x3c010001, 0xac2254a0, 
-0x3e00008, 0x0, 0x0, 0x27bdffd8, 
+0x2c422710, 0x14400003, 0x24020009, 0x3c010001, 
+0xac2254a0, 0x3e00008, 0x0, 0x27bdffd8, 
 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 
 0xafb10014, 0xc08821, 0xafb00010, 0x8021, 
 0xafbf0020, 0xa6200000, 0xc004cab, 0x24040001, 
@@ -3923,14 +3932,14 @@
 0x621825, 0x1460000d, 0x38a30030, 0x2c630001, 
 0x38a20400, 0x2c420001, 0x621825, 0x14600007, 
 0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, 
-0x621825, 0x10600005, 0x0, 0xc00429f, 
-0x0, 0x8004d2d, 0x2402000e, 0xc0043e1, 
+0x621825, 0x10600005, 0x0, 0xc00429b, 
+0x0, 0x8004d2d, 0x2402000e, 0xc0043dd, 
 0x0, 0x3c050001, 0x8ca55488, 0xc0050b3, 
 0x2021, 0x3c030001, 0x8c635488, 0x24020004, 
 0x14620005, 0x2403fffb, 0x3c020001, 0x8c425484, 
 0x8004d29, 0x2403fff7, 0x3c020001, 0x8c425484, 
 0x431024, 0x3c010001, 0xac225484, 0x2402000e, 
-0x3c010001, 0xc00429f, 0xac227560, 0x8004f27, 
+0x3c010001, 0xc00429b, 0xac227560, 0x8004f27, 
 0x0, 0x8f820220, 0x3c030400, 0x431024, 
 0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, 
 0x8c42756c, 0xa32024, 0x431024, 0x1482000c, 
@@ -3954,10 +3963,10 @@
 0x3c010001, 0xac207590, 0x3c010001, 0xac207570, 
 0x3c010001, 0xac20756c, 0x3c010001, 0xac207594, 
 0x3c010001, 0xac207588, 0x3c010001, 0xac207580, 
-0xc0047cc, 0xaf800224, 0x24020002, 0x3c010001, 
+0xc0047cd, 0xaf800224, 0x24020002, 0x3c010001, 
 0xac227560, 0x3c020001, 0x8c4275a0, 0x14400056, 
 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 
-0xc00429f, 0xaee20000, 0xaf800204, 0x8f820200, 
+0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200, 
 0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, 
 0xac2075b0, 0x8f830054, 0x3c020001, 0x8c427588, 
 0x24040001, 0x3c010001, 0xac24759c, 0x24420001, 
@@ -4039,7 +4048,7 @@
 0x2c422710, 0x1440003a, 0x0, 0x3c020001, 
 0x8c4275a0, 0x10400029, 0x2402000e, 0x3c030001, 
 0x8c6375b4, 0x3c010001, 0x14600015, 0xac227560, 
-0xc0043e1, 0x0, 0x3c050001, 0x8ca55488, 
+0xc0043dd, 0x0, 0x3c050001, 0x8ca55488, 
 0xc0050b3, 0x2021, 0x3c030001, 0x8c635488, 
 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, 
 0x8c425484, 0x8004ef2, 0x2403fff7, 0x3c020001, 
@@ -4055,7 +4064,7 @@
 0x3c020001, 0x8c42756c, 0x1440000b, 0x0, 
 0x24020002, 0x3c010001, 0x8004f23, 0xac227560, 
 0x3c020001, 0x8c427590, 0x10400003, 0x0, 
-0xc00429f, 0x0, 0x8f820220, 0x3c03f700, 
+0xc00429b, 0x0, 0x8f820220, 0x3c03f700, 
 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 
 0x27bd0018, 0x3c030001, 0x246375b8, 0x8c620000, 
 0x10400005, 0x34422000, 0x3c010001, 0xac2275ac, 
@@ -4086,14 +4095,14 @@
 0x431025, 0xaf820220, 0x24020100, 0x3c010001, 
 0xac2275d4, 0x3c010001, 0x8004fa4, 0xac2375dc, 
 0x34a5ffff, 0x3c040001, 0x24845398, 0xafa30010, 
-0xc002407, 0xafa00014, 0x8004fa4, 0x0, 
+0xc002403, 0xafa00014, 0x8004fa4, 0x0, 
 0x24020030, 0x3c010001, 0xac2275b8, 0x8fbf0018, 
 0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, 
 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, 
 0xafb00020, 0xc08021, 0x3c040001, 0x248453b0, 
 0x3c050009, 0x3c020001, 0x8c425488, 0x34a59001, 
 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, 
-0xa7a0001a, 0xafb00014, 0xc002407, 0xafa20010, 
+0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010, 
 0x24020002, 0x126200ed, 0x2e620003, 0x10400005, 
 0x24020001, 0x1262000a, 0x3c02fffb, 0x80050ac, 
 0x0, 0x24020004, 0x1262006d, 0x24020008, 
@@ -4114,8 +4123,8 @@
 0x34420001, 0xc0048ee, 0xa4e20002, 0x24040001, 
 0x2821, 0xc0048ee, 0x27a60018, 0x3c020001, 
 0x8c425488, 0x24110001, 0x3c010001, 0xac315494, 
-0x14530004, 0x32028000, 0xc00429f, 0x0, 
-0x32028000, 0x10400099, 0x0, 0xc00429f, 
+0x14530004, 0x32028000, 0xc00429b, 0x0, 
+0x32028000, 0x10400099, 0x0, 0xc00429b, 
 0x0, 0x24020002, 0x3c010001, 0xac31548c, 
 0x3c010001, 0x80050ac, 0xac225488, 0x24040001, 
 0x24050004, 0x27b0001a, 0xc0048ee, 0x2003021, 
@@ -4153,7 +4162,7 @@
 0x3c010001, 0x230821, 0x80050a5, 0xac2275dc, 
 0x111140, 0x3c010001, 0x220821, 0xac2075dc, 
 0x3c030001, 0x8c635488, 0x24020001, 0x10620003, 
-0x0, 0xc00429f, 0x0, 0x8fbf0030, 
+0x0, 0xc00429b, 0x0, 0x8fbf0030, 
 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 
 0x3e00008, 0x27bd0038, 0x27bdffd0, 0xafb40028, 
 0x80a021, 0xafb20020, 0x9021, 0xafb30024, 
@@ -4227,19 +4236,19 @@
 0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, 
 0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, 
 0x2228824, 0x3c010001, 0x230821, 0xac2075d0, 
-0x3c010001, 0x230821, 0xac2075d8, 0xc0047cc, 
+0x3c010001, 0x230821, 0xac2075d8, 0xc0047cd, 
 0x0, 0xaf900200, 0xaf930220, 0x8f820220, 
 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
 0x34420002, 0xaf820220, 0x80051eb, 0x141140, 
-0x8f820200, 0x2403fffd, 0x431024, 0xc0047cc, 
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, 
+0x8f820200, 0x2403fffd, 0x431024, 0xc0047cd, 
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, 
 0x2228824, 0x141140, 0x3c010001, 0x220821, 
 0x8005240, 0xac3175c4, 0x149140, 0x3c040001, 
 0x922021, 0x8c8475c8, 0x3c110001, 0x2328821, 
 0x8e3175c0, 0x3c024000, 0x821024, 0x14400011, 
 0x0, 0x3c020001, 0x8c425538, 0x14400006, 
-0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cc, 
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429f, 
+0x3c02bfff, 0x8f820200, 0x34420002, 0xc0047cd, 
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, 
 0x2228824, 0x3c010001, 0x320821, 0x8005240, 
 0xac3175c0, 0x3c020001, 0x8c425538, 0x10400005, 
 0x3c020020, 0x3c020001, 0x8c425514, 0x1040002b, 
@@ -4251,7 +4260,7 @@
 0x3c010001, 0x230821, 0xac2275dc, 0x8005231, 
 0x2629825, 0x141140, 0x3c010001, 0x220821, 
 0xac2075dc, 0x3c02fffe, 0x3442ffff, 0x2629824, 
-0xc0047cc, 0x0, 0xaf900200, 0xaf930220, 
+0xc0047cd, 0x0, 0xaf900200, 0xaf930220, 
 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 
 0x8f820220, 0x34420002, 0xaf820220, 0x141140, 
 0x3c010001, 0x220821, 0xac3175c0, 0x8fbf0024, 
@@ -4329,10 +4338,10 @@
 0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, 
 0x31333a34, 0x30207368, 0x75616e67, 0x20457870, 
 0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, 
-0x23312054, 0x75652041, 0x70722032, 0x30203137, 
-0x3a32313a, 0x30382050, 0x44542031, 0x39393900, 
+0x23312054, 0x68752041, 0x75672031, 0x32203135, 
+0x3a34393a, 0x35332050, 0x44542031, 0x39393900, 
 0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, 
-0x2031373a, 0x32313a30, 0x38000000, 0x46575f43, 
+0x2031353a, 0x34393a35, 0x33000000, 0x46575f43, 
 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 
 0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, 
 0x4f53543a, 0x20636f6d, 0x70757465, 0x0, 
@@ -4357,17 +4366,17 @@
 0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, 
 0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845, 
 0x0, 0x756e6b72, 0x64747970, 0x65000000, 
-0x0, 0xacdc, 0xacdc, 0xadac, 
-0xaac0, 0xaac0, 0xadac, 0xadac, 
-0xadac, 0xadac, 0xadac, 0xadac, 
-0xadac, 0xadac, 0xadac, 0xadac, 
-0xadac, 0xadac, 0xadac, 0xad8c, 
-0x0, 0xbcb8, 0xbcb8, 0xbd80, 
-0xae5c, 0xb068, 0xbd80, 0xbd80, 
-0xbd80, 0xbd80, 0xbd80, 0xbd80, 
-0xbd80, 0xbd80, 0xbd80, 0xbd80, 
-0xbd80, 0xbd80, 0xbd80, 0xbd64, 
-0xb050, 0x24486561, 0x6465723a, 0x202f7072, 
+0x0, 0xaccc, 0xaccc, 0xad9c, 
+0xaab0, 0xaab0, 0xad9c, 0xad9c, 
+0xad9c, 0xad9c, 0xad9c, 0xad9c, 
+0xad9c, 0xad9c, 0xad9c, 0xad9c, 
+0xad9c, 0xad9c, 0xad9c, 0xad7c, 
+0x0, 0xbca8, 0xbca8, 0xbd70, 
+0xae4c, 0xb058, 0xbd70, 0xbd70, 
+0xbd70, 0xbd70, 0xbd70, 0xbd70, 
+0xbd70, 0xbd70, 0xbd70, 0xbd70, 
+0xbd70, 0xbd70, 0xbd70, 0xbd54, 
+0xb040, 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 
 0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e, 
@@ -4381,17 +4390,17 @@
 0x0, 0x66726d32, 0x4c726753, 0x0, 
 0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146, 
 0x0, 0x3f724a42, 0x64446d46, 0x0, 
-0x0, 0xf688, 0xf688, 0xf688, 
-0xf688, 0xf688, 0xf688, 0xf688, 
-0xf688, 0xf688, 0xf688, 0xf688, 
-0xf688, 0xf688, 0xf688, 0xf688, 
-0xf680, 0xf680, 0xf680, 0x572d444d, 
-0x41456e46, 0x0, 0x0, 0xfdd0, 
-0x1016c, 0xfdec, 0x1016c, 0x1016c, 
-0x1016c, 0x1016c, 0x1016c, 0x1016c, 
-0xf714, 0x1016c, 0x1016c, 0x1016c, 
-0x1016c, 0x1016c, 0x10164, 0x10164, 
-0x10164, 0x24486561, 0x6465723a, 0x202f7072, 
+0x0, 0xf678, 0xf678, 0xf678, 
+0xf678, 0xf678, 0xf678, 0xf678, 
+0xf678, 0xf678, 0xf678, 0xf678, 
+0xf678, 0xf678, 0xf678, 0xf678, 
+0xf670, 0xf670, 0xf670, 0x572d444d, 
+0x41456e46, 0x0, 0x0, 0xfdc0, 
+0x1015c, 0xfddc, 0x1015c, 0x1015c, 
+0x1015c, 0x1015c, 0x1015c, 0x1015c, 
+0xf704, 0x1015c, 0x1015c, 0x1015c, 
+0x1015c, 0x1015c, 0x10154, 0x10154, 
+0x10154, 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, 
 0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31, 
@@ -4410,13 +4419,13 @@
 0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, 
 0x3a31333a, 0x33392073, 0x6875616e, 0x67204578, 
 0x70202400, 0x50726f62, 0x65506879, 0x0, 
-0x6c6e6b41, 0x53535254, 0x0, 0x11994, 
-0x119cc, 0x119e4, 0x11a18, 0x11a44, 
-0x11a58, 0x11a94, 0x11e04, 0x11b6c, 
-0x11bac, 0x11bd8, 0x11c18, 0x11c48, 
-0x11c84, 0x11cb8, 0x11e04, 0x12048, 
-0x12060, 0x12088, 0x120a8, 0x120d0, 
-0x12200, 0x12228, 0x1227c, 0x122a4, 
+0x6c6e6b41, 0x53535254, 0x0, 0x11998, 
+0x119d0, 0x119e8, 0x11a1c, 0x11a48, 
+0x11a5c, 0x11a98, 0x11e08, 0x11b70, 
+0x11bb0, 0x11bdc, 0x11c1c, 0x11c4c, 
+0x11c88, 0x11cbc, 0x11e08, 0x1204c, 
+0x12064, 0x1208c, 0x120ac, 0x120d4, 
+0x12204, 0x1222c, 0x12280, 0x122a8, 
 0x0, 0x1250c, 0x125dc, 0x126b4, 
 0x12784, 0x127e0, 0x128bc, 0x128e4, 
 0x129c0, 0x129e8, 0x12b90, 0x12bb8, 
@@ -4452,28 +4461,29 @@
 0x0, 0x0, 0x0, 0x2, 
 0x0, 0x0, 0x30001, 0x1, 
 0x30201, 0x0, 0x0, 0x0 };
+#endif
 /* Generated by genfw.c */
-int tigon2FwReleaseMajor = 0xc;
-int tigon2FwReleaseMinor = 0x3;
-int tigon2FwReleaseFix = 0xa;
-u32 tigon2FwStartAddr = 0x00004000;
-u32 tigon2FwTextAddr = 0x00004000;
-int tigon2FwTextLen = 0xed40;
-u32 tigon2FwRodataAddr = 0x00012d40;
-int tigon2FwRodataLen = 0xff0;
-u32 tigon2FwDataAddr = 0x00013d60;
-int tigon2FwDataLen = 0x170;
-u32 tigon2FwSbssAddr = 0x00013ed0;
-int tigon2FwSbssLen = 0xbc;
-u32 tigon2FwBssAddr = 0x00013f90;
-int tigon2FwBssLen = 0x20c0;
+#define tigon2FwReleaseMajor 0xc
+#define tigon2FwReleaseMinor 0x3
+#define tigon2FwReleaseFix 0xd
+#define tigon2FwStartAddr 0x00004000
+#define tigon2FwTextAddr 0x00004000
+#define tigon2FwTextLen 0xeca0
+#define tigon2FwRodataAddr 0x00012ca0
+#define tigon2FwRodataLen 0xff0
+#define tigon2FwDataAddr 0x00013cc0
+#define tigon2FwDataLen 0x170
+#define tigon2FwSbssAddr 0x00013e30
+#define tigon2FwSbssLen 0xbc
+#define tigon2FwBssAddr 0x00013ef0
+#define tigon2FwBssLen 0x20c0
 u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x0, 
 0x10000003, 0x0, 0xd, 0xd, 
-0x3c1d0001, 0x8fbd3db0, 0x3a0f021, 0x3c100000, 
+0x3c1d0001, 0x8fbd3d10, 0x3a0f021, 0x3c100000, 
 0x26104000, 0xc0010c0, 0x0, 0xd, 
-0x3c1d0001, 0x8fbd3db4, 0x3a0f021, 0x3c100000, 
-0x26104000, 0xc00178d, 0x0, 0xd, 
+0x3c1d0001, 0x8fbd3d14, 0x3a0f021, 0x3c100000, 
+0x26104000, 0xc00178e, 0x0, 0xd, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
@@ -4485,22 +4495,22 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x2000008, 
-0x0, 0x80016de, 0x3c0a0001, 0x80016de, 
-0x3c0a0002, 0x80016de, 0x0, 0x8002afd, 
-0x0, 0x8002aa0, 0x0, 0x80016de, 
-0x3c0a0004, 0x80030d1, 0x0, 0x8001a0e, 
-0x0, 0x8003779, 0x0, 0x8003720, 
-0x0, 0x80016de, 0x3c0a0006, 0x80037e7, 
-0x3c0a0007, 0x80016de, 0x3c0a0008, 0x80016de, 
-0x3c0a0009, 0x800383f, 0x0, 0x8002cf7, 
-0x0, 0x80016de, 0x3c0a000b, 0x80016de, 
-0x3c0a000c, 0x80016de, 0x3c0a000d, 0x80027c5, 
-0x0, 0x800275a, 0x0, 0x80016de, 
-0x3c0a000e, 0x8001f28, 0x0, 0x8001920, 
-0x0, 0x80019c0, 0x0, 0x8003aa8, 
-0x0, 0x8003a96, 0x0, 0x80016de, 
-0x0, 0x80018c6, 0x0, 0x80016de, 
-0x0, 0x80016de, 0x3c0a0013, 0x80016de, 
+0x0, 0x80016dd, 0x3c0a0001, 0x80016dd, 
+0x3c0a0002, 0x80016dd, 0x0, 0x8002ab5, 
+0x0, 0x8002a58, 0x0, 0x80016dd, 
+0x3c0a0004, 0x800306c, 0x0, 0x8001a07, 
+0x0, 0x80036c3, 0x0, 0x8004aad, 
+0x0, 0x80016dd, 0x3c0a0006, 0x8003731, 
+0x3c0a0007, 0x80016dd, 0x3c0a0008, 0x80016dd, 
+0x3c0a0009, 0x8003789, 0x0, 0x8002caf, 
+0x0, 0x80016dd, 0x3c0a000b, 0x80016dd, 
+0x3c0a000c, 0x80016dd, 0x3c0a000d, 0x800277b, 
+0x0, 0x8002710, 0x0, 0x80016dd, 
+0x3c0a000e, 0x8001f20, 0x0, 0x8001919, 
+0x0, 0x80019b9, 0x0, 0x8003a08, 
+0x0, 0x80039f6, 0x0, 0x80016dd, 
+0x0, 0x80018c6, 0x0, 0x80016dd, 
+0x0, 0x80016dd, 0x3c0a0013, 0x80016dd, 
 0x3c0a0014, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
@@ -4518,511 +4528,511 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x27bdffe0, 
 0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, 
-0x24030003, 0xaf8300ec, 0x34420004, 0xc0029e8, 
-0xaf820140, 0x3c0100c0, 0xc001712, 0xac203ffc, 
-0x403021, 0x3c020008, 0x3c010001, 0xac263ee8, 
-0x50c2000d, 0x3c020003, 0x3c100010, 0x10d00009, 
-0x24050100, 0x3c040001, 0x24842df4, 0x3821, 
-0xafa00010, 0xc002a03, 0xafa00014, 0x3c010001, 
-0xac303ee8, 0x3c020003, 0x34422000, 0x3c010001, 
-0xac223ef8, 0x24020008, 0x3c010001, 0xac223f00, 
-0x2402001f, 0x3c010001, 0xac223f10, 0x24020016, 
-0x3c010001, 0xac223ee4, 0x3c05fffe, 0x34a56f08, 
-0x3c020001, 0x8c423ee8, 0x3c030001, 0x24636050, 
-0x3c040001, 0x8c843d64, 0x431023, 0x14800002, 
+0x24030003, 0xaf8300ec, 0x34420004, 0xc0029a0, 
+0xaf820140, 0x3c0100c0, 0xc001711, 0xac203ffc, 
+0x403021, 0x3c020008, 0x3c010001, 0xac263e48, 
+0x50c2000d, 0x24020008, 0x3c100010, 0x10d00009, 
+0x24050100, 0x3c040001, 0x24842d54, 0x3821, 
+0xafa00010, 0xc0029bb, 0xafa00014, 0x3c010001, 
+0xac303e48, 0x24020008, 0x3c010001, 0xac223e60, 
+0x2402001f, 0x3c010001, 0xac223e70, 0x24020016, 
+0x3c010001, 0xac223e44, 0x3c05fffe, 0x34a56f08, 
+0x3c020001, 0x8c423e48, 0x3c030001, 0x24635fb0, 
+0x3c040001, 0x8c843cc4, 0x431023, 0x14800002, 
 0x458021, 0x2610fa48, 0x2402f000, 0x2028024, 
-0xc001734, 0x2002021, 0x2022823, 0x3c040020, 
+0xc001733, 0x2002021, 0x2022823, 0x3c040020, 
 0x821823, 0x651823, 0x247bb000, 0x3c03fffe, 
 0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000, 
-0x3c070001, 0x8ce73d60, 0x3c0300bf, 0x3463e000, 
-0x852023, 0x3c010001, 0xac243ef4, 0x822023, 
-0x3c010001, 0xac223ed0, 0x27620ffc, 0x3c010001, 
-0xac223db0, 0x27621ffc, 0xdb3023, 0x7b1823, 
-0x3c010001, 0xac253edc, 0x3c010001, 0xac243ed4, 
-0x3c010001, 0xac223db4, 0xaf860150, 0x10e00011, 
-0xaf830250, 0x3c1d0001, 0x8fbd3d6c, 0x3a0f021, 
-0xc0016f8, 0x0, 0x3c020001, 0x8c423d70, 
-0x3c030001, 0x8c633d74, 0x2442fe00, 0x24630200, 
-0x3c010001, 0xac223d70, 0x3c010001, 0x10000004, 
-0xac233d74, 0x3c1d0001, 0x8fbd3db0, 0x3a0f021, 
-0x3c020001, 0x8c423d64, 0x1040000d, 0x26fafa48, 
-0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, 
-0x3c1a0001, 0x8f5a3d74, 0x2442fa48, 0x246305b8, 
-0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, 
-0x3c020001, 0x8c423d68, 0x14400003, 0x0, 
-0x3c010001, 0xac203d70, 0xc00114d, 0x0, 
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 
-0x3c020001, 0x8c423d70, 0x3c030001, 0x8c633d74, 
-0x27bdffa0, 0xafb00040, 0x3c100001, 0x8e1037d8, 
-0x3c040001, 0x24842e00, 0xafbf0058, 0xafbe0054, 
-0xafb50050, 0xafb3004c, 0xafb20048, 0xafb10044, 
-0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, 
-0x8f860040, 0x24050200, 0xc002a03, 0x2003821, 
-0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, 
-0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, 
-0x24842e08, 0xa3ae003f, 0xafa00010, 0xafa00014, 
-0x8f860040, 0x24050300, 0xc002a03, 0x2003821, 
-0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 
-0xaf800048, 0x8f820048, 0x14400005, 0x0, 
-0xaf800048, 0x8f820048, 0x10400004, 0x0, 
-0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, 
-0x2e02021, 0x3c050001, 0xc002a70, 0x34a540f8, 
-0x3402021, 0xc002a70, 0x240505b8, 0x3c020001, 
-0x8c423ef4, 0x3c0d0001, 0x8dad3ed4, 0x3c030001, 
-0x8c633ed0, 0x3c080001, 0x8d083edc, 0x3c090001, 
-0x8d293ef8, 0x3c0a0001, 0x8d4a3f00, 0x3c0b0001, 
-0x8d6b3f10, 0x3c0c0001, 0x8d8c3ee4, 0x3c040001, 
-0x24842e14, 0x24050400, 0xaf420130, 0x8f420130, 
-0x24060001, 0x24070001, 0xaf400000, 0xaf4d012c, 
-0xaf430138, 0xaf48013c, 0xaf490140, 0xaf4a0144, 
-0xaf4b0148, 0xaf4c014c, 0x2442ff80, 0xaf420134, 
-0x24020001, 0xafa20010, 0xc002a03, 0xafa00014, 
-0x8f42012c, 0xafa20010, 0x8f420130, 0xafa20014, 
-0x8f460138, 0x8f47013c, 0x3c040001, 0x24842e20, 
-0xc002a03, 0x24050500, 0xafb70010, 0xafba0014, 
-0x8f460140, 0x8f470144, 0x3c040001, 0x24842e2c, 
-0xc002a03, 0x24050600, 0x3c020001, 0x8c423ee8, 
-0x3603821, 0x3c060001, 0x24c66050, 0x2448ffff, 
-0x1061824, 0xe81024, 0x43102b, 0x10400006, 
-0x24050900, 0x3c040001, 0x24842e38, 0xafa80010, 
-0xc002a03, 0xafa00014, 0x8f82000c, 0xafa20010, 
-0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, 
-0x3c040001, 0x24842e44, 0xc002a03, 0x24051000, 
-0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, 
-0x3c040001, 0x24842e4c, 0x24051100, 0xafa20010, 
-0xc002a03, 0xafa30014, 0xaf800054, 0xaf80011c, 
-0x8c020218, 0x30420002, 0x10400009, 0x0, 
-0x8c020220, 0x3c030002, 0x34630004, 0x431025, 
-0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004, 
-0x8c020220, 0x3c030002, 0x34630006, 0x431025, 
-0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014, 
-0x8c020218, 0x30420010, 0x1040000a, 0x0, 
-0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220, 
-0x3c03000a, 0x34630004, 0x431025, 0x10000009, 
-0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006, 
-0x431025, 0xaf420008, 0x8c02021c, 0x34420006, 
-0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0, 
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
-0x0, 0x8c040208, 0x8c05020c, 0x26e20028, 
-0xaee20020, 0x24020490, 0xaee20010, 0xaee40008, 
-0xaee5000c, 0x26e40008, 0x8c820000, 0x8c830004, 
-0xaf820090, 0xaf830094, 0x8c820018, 0xaf8200b4, 
-0x9482000a, 0xaf82009c, 0x8f8200b0, 0x8f430014, 
-0x431025, 0xaf8200b0, 0x8f8200b0, 0x30420004, 
-0x1440fffd, 0x24051200, 0x96e20472, 0x96e60452, 
-0x96e70462, 0xafa20010, 0x96e20482, 0x3c040001, 
-0x24842e54, 0xc002a03, 0xafa20014, 0x96f00452, 
-0x32020001, 0x10400002, 0xb021, 0x24160001, 
-0x32020002, 0x54400001, 0x36d60002, 0x32020008, 
-0x54400001, 0x36d60004, 0x32020010, 0x54400001, 
-0x36d60008, 0x32020020, 0x54400001, 0x36d60010, 
-0x32020040, 0x54400001, 0x36d60020, 0x32020080, 
-0x54400001, 0x36d60040, 0x96e60482, 0x30c20200, 
-0x54400001, 0x36d64000, 0x96e30472, 0x30620200, 
-0x10400003, 0x30620100, 0x10000003, 0x36d62000, 
-0x54400001, 0x36d61000, 0x96f00462, 0x32c24000, 
-0x14400004, 0x3207009b, 0x30c2009b, 0x14e20007, 
-0x240e0001, 0x32c22000, 0x1440000d, 0x32020001, 
-0x3062009b, 0x10e20009, 0x240e0001, 0x3c040001, 
-0x24842e60, 0x24051300, 0x2003821, 0xa3ae003f, 
-0xafa30010, 0xc002a03, 0xafa00014, 0x32020001, 
-0x54400001, 0x36d60080, 0x32020002, 0x54400001, 
-0x36d60100, 0x32020008, 0x54400001, 0x36d60200, 
-0x32020010, 0x54400001, 0x36d60400, 0x32020080, 
-0x54400001, 0x36d60800, 0x8c020218, 0x30420200, 
-0x10400002, 0x3c020008, 0x2c2b025, 0x8c020218, 
-0x30420800, 0x10400002, 0x3c020080, 0x2c2b025, 
-0x8c020218, 0x30420400, 0x10400002, 0x3c020100, 
-0x2c2b025, 0x8c020218, 0x30420100, 0x10400002, 
-0x3c020200, 0x2c2b025, 0x8c020218, 0x30420080, 
-0x10400002, 0x3c020400, 0x2c2b025, 0x8c020218, 
-0x30422000, 0x10400002, 0x3c020010, 0x2c2b025, 
-0x8c020218, 0x30424000, 0x10400002, 0x3c020020, 
-0x2c2b025, 0x8c020218, 0x30421000, 0x10400002, 
-0x3c020040, 0x2c2b025, 0x8ee20498, 0x8ee3049c, 
-0xaf420150, 0xaf430154, 0x8ee204a0, 0x8ee304a4, 
-0xaf420158, 0xaf43015c, 0x8ee204a8, 0x8ee304ac, 
-0xaf420160, 0xaf430164, 0x8ee20428, 0x8ee3042c, 
-0xaf420168, 0xaf43016c, 0x8ee20448, 0x8ee3044c, 
-0xaf420170, 0xaf430174, 0x8ee20458, 0x8ee3045c, 
-0xaf420178, 0xaf43017c, 0x8ee20468, 0x8ee3046c, 
-0xaf420180, 0xaf430184, 0x8ee20478, 0x8ee3047c, 
-0xaf420188, 0xaf43018c, 0x8ee20488, 0x8ee3048c, 
-0xaf420190, 0xaf430194, 0x8ee204b0, 0x8ee304b4, 
-0x24040080, 0xaf420198, 0xaf43019c, 0xc002a70, 
-0x24050080, 0x8c02025c, 0x27440214, 0xaf4201e0, 
-0x8c020260, 0x24050200, 0x24060008, 0xc002a87, 
-0xaf4201e8, 0x3c043b9a, 0x3484ca00, 0x3821, 
-0x24020006, 0x24030002, 0xaf4201e4, 0x240203e8, 
-0xaf4301f4, 0xaf4301f0, 0xaf4401ec, 0xaf420284, 
-0x24020001, 0xaf430280, 0xaf42028c, 0x3c030001, 
-0x671821, 0x90633d78, 0x3471021, 0x24e70001, 
-0xa043021c, 0x2ce2000f, 0x1440fff8, 0x3471821, 
-0x24e70001, 0x3c080001, 0x350840f8, 0x8f820040, 
-0x3c040001, 0x24842e6c, 0x24051400, 0x21702, 
-0x24420030, 0xa062021c, 0x3471021, 0xa040021c, 
-0x8c070218, 0x2c03021, 0x240205b8, 0xafa20010, 
-0xc002a03, 0xafa80014, 0x3c040001, 0x24842e78, 
-0x3c050000, 0x24a55b3c, 0x24060010, 0x27b10030, 
-0x2203821, 0x27b30034, 0xc001750, 0xafb30010, 
-0x3c030001, 0x8c633d68, 0x1060000a, 0x408021, 
-0x8fa30030, 0x2405ff00, 0x8fa20034, 0x246400ff, 
-0x852024, 0x831823, 0x431023, 0xafa20034, 
-0xafa40030, 0xafb30010, 0x3c040001, 0x24842e84, 
-0x3c050000, 0x24a54100, 0x24060108, 0xc001750, 
-0x2203821, 0x409021, 0x32c20003, 0x50400045, 
-0x2203821, 0x8f820050, 0x3c030010, 0x431024, 
+0x3c070001, 0x8ce73cc0, 0x3c0300bf, 0x3463e000, 
+0x852023, 0x3c010001, 0xac243e54, 0x822023, 
+0x3c010001, 0xac253e3c, 0x52842, 0x3c010001, 
+0xac223e30, 0x27620ffc, 0x3c010001, 0xac223d10, 
+0x27621ffc, 0xdb3023, 0x7b1823, 0x3c010001, 
+0xac243e34, 0x3c010001, 0xac253e58, 0x3c010001, 
+0xac223d14, 0xaf860150, 0x10e00011, 0xaf830250, 
+0x3c1d0001, 0x8fbd3ccc, 0x3a0f021, 0xc0016f7, 
+0x0, 0x3c020001, 0x8c423cd0, 0x3c030001, 
+0x8c633cd4, 0x2442fe00, 0x24630200, 0x3c010001, 
+0xac223cd0, 0x3c010001, 0x10000004, 0xac233cd4, 
+0x3c1d0001, 0x8fbd3d10, 0x3a0f021, 0x3c020001, 
+0x8c423cc4, 0x1040000d, 0x26fafa48, 0x3c020001, 
+0x8c423cd0, 0x3c030001, 0x8c633cd4, 0x3c1a0001, 
+0x8f5a3cd4, 0x2442fa48, 0x246305b8, 0x3c010001, 
+0xac223cd0, 0x3c010001, 0xac233cd4, 0x3c020001, 
+0x8c423cc8, 0x14400003, 0x0, 0x3c010001, 
+0xac203cd0, 0xc00114c, 0x0, 0x8fbf001c, 
+0x8fb00018, 0x3e00008, 0x27bd0020, 0x3c020001, 
+0x8c423cd0, 0x3c030001, 0x8c633cd4, 0x27bdffa0, 
+0xafb00040, 0x3c100001, 0x8e103738, 0x3c040001, 
+0x24842d60, 0xafbf0058, 0xafbe0054, 0xafb50050, 
+0xafb3004c, 0xafb20048, 0xafb10044, 0xafa20034, 
+0xafa30030, 0xafa00010, 0xafa00014, 0x8f860040, 
+0x24050200, 0xc0029bb, 0x2003821, 0x8f830040, 
+0x3c02f000, 0x621824, 0x3c026000, 0x1062000b, 
+0xa3a0003f, 0x240e0001, 0x3c040001, 0x24842d68, 
+0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f860040, 
+0x24050300, 0xc0029bb, 0x2003821, 0x8f820240, 
+0x3c030001, 0x431025, 0xaf820240, 0xaf800048, 
+0x8f820048, 0x14400005, 0x0, 0xaf800048, 
+0x8f820048, 0x10400004, 0x0, 0xaf800048, 
+0x10000003, 0x2e02021, 0xaf80004c, 0x2e02021, 
+0x3c050001, 0xc002a28, 0x34a540f8, 0x3402021, 
+0xc002a28, 0x240505b8, 0x3c020001, 0x8c423e54, 
+0x3c0d0001, 0x8dad3e34, 0x3c030001, 0x8c633e30, 
+0x3c080001, 0x8d083e3c, 0x3c090001, 0x8d293e58, 
+0x3c0a0001, 0x8d4a3e60, 0x3c0b0001, 0x8d6b3e70, 
+0x3c0c0001, 0x8d8c3e44, 0x3c040001, 0x24842d74, 
+0x24050400, 0xaf420130, 0x8f420130, 0x24060001, 
+0x24070001, 0xaf400000, 0xaf4d012c, 0xaf430138, 
+0xaf48013c, 0xaf490140, 0xaf4a0144, 0xaf4b0148, 
+0xaf4c014c, 0x2442ff80, 0xaf420134, 0x24020001, 
+0xafa20010, 0xc0029bb, 0xafa00014, 0x8f42012c, 
+0xafa20010, 0x8f420130, 0xafa20014, 0x8f460138, 
+0x8f47013c, 0x3c040001, 0x24842d80, 0xc0029bb, 
+0x24050500, 0xafb70010, 0xafba0014, 0x8f460140, 
+0x8f470144, 0x3c040001, 0x24842d8c, 0xc0029bb, 
+0x24050600, 0x3c020001, 0x8c423e48, 0x3603821, 
+0x3c060001, 0x24c65fb0, 0x2448ffff, 0x1061824, 
+0xe81024, 0x43102b, 0x10400006, 0x24050900, 
+0x3c040001, 0x24842d98, 0xafa80010, 0xc0029bb, 
+0xafa00014, 0x8f82000c, 0xafa20010, 0x8f82003c, 
+0xafa20014, 0x8f860000, 0x8f870004, 0x3c040001, 
+0x24842da4, 0xc0029bb, 0x24051000, 0x8c020220, 
+0x8c030224, 0x8c060218, 0x8c07021c, 0x3c040001, 
+0x24842dac, 0x24051100, 0xafa20010, 0xc0029bb, 
+0xafa30014, 0xaf800054, 0xaf80011c, 0x8c020218, 
+0x30420002, 0x10400009, 0x0, 0x8c020220, 
+0x3c030002, 0x34630004, 0x431025, 0xaf42000c, 
+0x8c02021c, 0x10000008, 0x34420004, 0x8c020220, 
+0x3c030002, 0x34630006, 0x431025, 0xaf42000c, 
+0x8c02021c, 0x34420006, 0xaf420014, 0x8c020218, 
+0x30420010, 0x1040000a, 0x0, 0x8c02021c, 
+0x34420004, 0xaf420010, 0x8c020220, 0x3c03000a, 
+0x34630004, 0x431025, 0x10000009, 0xaf420008, 
+0x8c020220, 0x3c03000a, 0x34630006, 0x431025, 
+0xaf420008, 0x8c02021c, 0x34420006, 0xaf420010, 
+0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054, 
+0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
+0x621023, 0x2c420065, 0x1440fffc, 0x0, 
+0x8c040208, 0x8c05020c, 0x26e20028, 0xaee20020, 
+0x24020490, 0xaee20010, 0xaee40008, 0xaee5000c, 
+0x26e40008, 0x8c820000, 0x8c830004, 0xaf820090, 
+0xaf830094, 0x8c820018, 0xaf8200b4, 0x9482000a, 
+0xaf82009c, 0x8f8200b0, 0x8f430014, 0x431025, 
+0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd, 
+0x24051200, 0x96e20472, 0x96e60452, 0x96e70462, 
+0xafa20010, 0x96e20482, 0x3c040001, 0x24842db4, 
+0xc0029bb, 0xafa20014, 0x96f00452, 0x32020001, 
+0x10400002, 0xb021, 0x24160001, 0x32020002, 
+0x54400001, 0x36d60002, 0x32020008, 0x54400001, 
+0x36d60004, 0x32020010, 0x54400001, 0x36d60008, 
+0x32020020, 0x54400001, 0x36d60010, 0x32020040, 
+0x54400001, 0x36d60020, 0x32020080, 0x54400001, 
+0x36d60040, 0x96e60482, 0x30c20200, 0x54400001, 
+0x36d64000, 0x96e30472, 0x30620200, 0x10400003, 
+0x30620100, 0x10000003, 0x36d62000, 0x54400001, 
+0x36d61000, 0x96f00462, 0x32c24000, 0x14400004, 
+0x3207009b, 0x30c2009b, 0x14e20007, 0x240e0001, 
+0x32c22000, 0x1440000d, 0x32020001, 0x3062009b, 
+0x10e20009, 0x240e0001, 0x3c040001, 0x24842dc0, 
+0x24051300, 0x2003821, 0xa3ae003f, 0xafa30010, 
+0xc0029bb, 0xafa00014, 0x32020001, 0x54400001, 
+0x36d60080, 0x32020002, 0x54400001, 0x36d60100, 
+0x32020008, 0x54400001, 0x36d60200, 0x32020010, 
+0x54400001, 0x36d60400, 0x32020080, 0x54400001, 
+0x36d60800, 0x8c020218, 0x30420200, 0x10400002, 
+0x3c020008, 0x2c2b025, 0x8c020218, 0x30420800, 
+0x10400002, 0x3c020080, 0x2c2b025, 0x8c020218, 
+0x30420400, 0x10400002, 0x3c020100, 0x2c2b025, 
+0x8c020218, 0x30420100, 0x10400002, 0x3c020200, 
+0x2c2b025, 0x8c020218, 0x30420080, 0x10400002, 
+0x3c020400, 0x2c2b025, 0x8c020218, 0x30422000, 
+0x10400002, 0x3c020010, 0x2c2b025, 0x8c020218, 
+0x30424000, 0x10400002, 0x3c020020, 0x2c2b025, 
+0x8c020218, 0x30421000, 0x10400002, 0x3c020040, 
+0x2c2b025, 0x8ee20498, 0x8ee3049c, 0xaf420150, 
+0xaf430154, 0x8ee204a0, 0x8ee304a4, 0xaf420158, 
+0xaf43015c, 0x8ee204a8, 0x8ee304ac, 0xaf420160, 
+0xaf430164, 0x8ee20428, 0x8ee3042c, 0xaf420168, 
+0xaf43016c, 0x8ee20448, 0x8ee3044c, 0xaf420170, 
+0xaf430174, 0x8ee20458, 0x8ee3045c, 0xaf420178, 
+0xaf43017c, 0x8ee20468, 0x8ee3046c, 0xaf420180, 
+0xaf430184, 0x8ee20478, 0x8ee3047c, 0xaf420188, 
+0xaf43018c, 0x8ee20488, 0x8ee3048c, 0xaf420190, 
+0xaf430194, 0x8ee204b0, 0x8ee304b4, 0x24040080, 
+0xaf420198, 0xaf43019c, 0xc002a28, 0x24050080, 
+0x8c02025c, 0x27440214, 0xaf4201e0, 0x8c020260, 
+0x24050200, 0x24060008, 0xc002a3f, 0xaf4201e8, 
+0x3c043b9a, 0x3484ca00, 0x3821, 0x24020006, 
+0x24030002, 0xaf4201e4, 0x240203e8, 0xaf4301f4, 
+0xaf4301f0, 0xaf4401ec, 0xaf420284, 0x24020001, 
+0xaf430280, 0xaf42028c, 0x3c030001, 0x671821, 
+0x90633cd8, 0x3471021, 0x24e70001, 0xa043021c, 
+0x2ce2000f, 0x1440fff8, 0x3471821, 0x24e70001, 
+0x3c080001, 0x350840f8, 0x8f820040, 0x3c040001, 
+0x24842dcc, 0x24051400, 0x21702, 0x24420030, 
+0xa062021c, 0x3471021, 0xa040021c, 0x8c070218, 
+0x2c03021, 0x240205b8, 0xafa20010, 0xc0029bb, 
+0xafa80014, 0x3c040001, 0x24842dd8, 0x3c050000, 
+0x24a55b38, 0x24060010, 0x27b10030, 0x2203821, 
+0x27b30034, 0xc001751, 0xafb30010, 0x3c030001, 
+0x8c633cc8, 0x1060000a, 0x408021, 0x8fa30030, 
+0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024, 
+0x831823, 0x431023, 0xafa20034, 0xafa40030, 
+0xafb30010, 0x3c040001, 0x24842de4, 0x3c050000, 
+0x24a54100, 0x24060108, 0xc001751, 0x2203821, 
+0x409021, 0x32c20003, 0x50400045, 0x2203821, 
+0x8f820050, 0x3c030010, 0x431024, 0x10400016, 
+0x0, 0x8c020218, 0x30420040, 0x1040000f, 
+0x24020001, 0x8f820050, 0x8c030218, 0x240e0001, 
+0x3c040001, 0x24842df0, 0xa3ae003f, 0xafa20010, 
+0xafa30014, 0x8f870040, 0x24051500, 0xc0029bb, 
+0x2c03021, 0x10000004, 0x0, 0x3c010001, 
+0x370821, 0xa02240f4, 0x3c040001, 0x24842dfc, 
+0x3c050001, 0x24a52c20, 0x3c060001, 0x24c62c8c, 
+0xc53023, 0x8f420010, 0x27b30030, 0x2603821, 
+0x27b10034, 0x34420a00, 0xaf420010, 0xc001751, 
+0xafb10010, 0x3c040001, 0x24842e10, 0x3c050001, 
+0x24a5af38, 0x3c060001, 0x24c6b2b4, 0xc53023, 
+0x2603821, 0xaf420108, 0xc001751, 0xafb10010, 
+0x3c040001, 0x24842e2c, 0x3c050001, 0x24a5b6c4, 
+0x3c060001, 0x24c6c1a8, 0xc53023, 0x2603821, 
+0x3c010001, 0xac223ea0, 0xc001751, 0xafb10010, 
+0x3c040001, 0x24842e44, 0x10000024, 0x24051600, 
+0x3c040001, 0x24842e4c, 0x3c050001, 0x24a59b0c, 
+0x3c060001, 0x24c69c38, 0xc53023, 0xc001751, 
+0xafb30010, 0x3c040001, 0x24842e5c, 0x3c050001, 
+0x24a5aad4, 0x3c060001, 0x24c6af30, 0xc53023, 
+0x2203821, 0xaf420108, 0xc001751, 0xafb30010, 
+0x3c040001, 0x24842e70, 0x3c050001, 0x24a5b2bc, 
+0x3c060001, 0x24c6b6bc, 0xc53023, 0x2203821, 
+0x3c010001, 0xac223ea0, 0xc001751, 0xafb30010, 
+0x3c040001, 0x24842e84, 0x24051650, 0x2c03021, 
+0x3821, 0x3c010001, 0xac223ea4, 0xafa00010, 
+0xc0029bb, 0xafa00014, 0x32c20020, 0x10400021, 
+0x27a70030, 0x3c040001, 0x24842e90, 0x3c050001, 
+0x24a5a960, 0x3c060001, 0x24c6aacc, 0xc53023, 
+0x24022000, 0xaf42001c, 0x27a20034, 0xc001751, 
+0xafa20010, 0x21900, 0x31982, 0x3c040800, 
+0x641825, 0xae430028, 0x24030010, 0xaf43003c, 
+0x96e30450, 0xaf430040, 0x8f430040, 0x3c040001, 
+0x24842ea4, 0xafa00014, 0xafa30010, 0x8f47001c, 
+0x24051660, 0x3c010001, 0xac223e9c, 0x10000025, 
+0x32c60020, 0x8ee20448, 0x8ee3044c, 0xaf43001c, 
+0x8f42001c, 0x2442e000, 0x2c422001, 0x1440000a, 
+0x240e0001, 0x3c040001, 0x24842eb0, 0xa3ae003f, 
+0xafa00010, 0xafa00014, 0x8f46001c, 0x24051700, 
+0xc0029bb, 0x3821, 0x3c020000, 0x24425b74, 
+0x21100, 0x21182, 0x3c030800, 0x431025, 
+0xae420028, 0x24020008, 0xaf42003c, 0x96e20450, 
+0xaf420040, 0x8f420040, 0x3c040001, 0x24842ebc, 
+0xafa00014, 0xafa20010, 0x8f47001c, 0x24051800, 
+0x32c60020, 0xc0029bb, 0x0, 0x3c030001, 
+0x8c633ea0, 0x3c050fff, 0x34a5ffff, 0x3c020001, 
+0x8c423ea4, 0x3c040800, 0x651824, 0x31882, 
+0x641825, 0x451024, 0x21082, 0x441025, 
+0xae420080, 0x32c20180, 0x10400056, 0xae430020, 
+0x8f82005c, 0x3c030080, 0x431024, 0x1040000d, 
+0x0, 0x8f820050, 0xafa20010, 0x8f82005c, 
+0x240e0001, 0x3c040001, 0x24842ec8, 0xa3ae003f, 
+0xafa20014, 0x8f870040, 0x24051900, 0xc0029bb, 
+0x2c03021, 0x8f820050, 0x3c030010, 0x431024, 
 0x10400016, 0x0, 0x8c020218, 0x30420040, 
 0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, 
-0x240e0001, 0x3c040001, 0x24842e90, 0xa3ae003f, 
-0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, 
-0xc002a03, 0x2c03021, 0x10000004, 0x0, 
+0x240e0001, 0x3c040001, 0x24842df0, 0xa3ae003f, 
+0xafa20010, 0xafa30014, 0x8f870040, 0x24052000, 
+0xc0029bb, 0x2c03021, 0x10000004, 0x0, 
 0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, 
-0x24842e9c, 0x3c050001, 0x24a59ce8, 0x3c060001, 
-0x24c69d60, 0xc53023, 0x8f420010, 0x27b30030, 
-0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, 
-0xc001750, 0xafb10010, 0x3c040001, 0x24842eb0, 
-0x3c050001, 0x24a5b058, 0x3c060001, 0x24c6b3d4, 
-0xc53023, 0x2603821, 0xaf420108, 0xc001750, 
-0xafb10010, 0x3c040001, 0x24842ecc, 0x3c050001, 
-0x24a5b7e4, 0x3c060001, 0x24c6c2c8, 0xc53023, 
-0x2603821, 0x3c010001, 0xac223f40, 0xc001750, 
-0xafb10010, 0x3c040001, 0x24842ee4, 0x10000024, 
-0x24051600, 0x3c040001, 0x24842eec, 0x3c050001, 
-0x24a59bb4, 0x3c060001, 0x24c69ce0, 0xc53023, 
-0xc001750, 0xafb30010, 0x3c040001, 0x24842efc, 
-0x3c050001, 0x24a5abf4, 0x3c060001, 0x24c6b050, 
-0xc53023, 0x2203821, 0xaf420108, 0xc001750, 
-0xafb30010, 0x3c040001, 0x24842f10, 0x3c050001, 
-0x24a5b3dc, 0x3c060001, 0x24c6b7dc, 0xc53023, 
-0x2203821, 0x3c010001, 0xac223f40, 0xc001750, 
-0xafb30010, 0x3c040001, 0x24842f24, 0x24051650, 
-0x2c03021, 0x3821, 0x3c010001, 0xac223f44, 
-0xafa00010, 0xc002a03, 0xafa00014, 0x32c20020, 
-0x10400021, 0x27a70030, 0x3c040001, 0x24842f30, 
-0x3c050001, 0x24a5aa80, 0x3c060001, 0x24c6abec, 
-0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, 
-0xc001750, 0xafa20010, 0x21900, 0x31982, 
-0x3c040800, 0x641825, 0xae430028, 0x24030010, 
-0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, 
-0x3c040001, 0x24842f44, 0xafa00014, 0xafa30010, 
-0x8f47001c, 0x24051660, 0x3c010001, 0xac223f3c, 
-0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, 
-0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, 
-0x1440000a, 0x240e0001, 0x3c040001, 0x24842f50, 
-0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, 
-0x24051700, 0xc002a03, 0x3821, 0x3c020000, 
-0x24425b78, 0x21100, 0x21182, 0x3c030800, 
-0x431025, 0xae420028, 0x24020008, 0xaf42003c, 
-0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, 
-0x24842f5c, 0xafa00014, 0xafa20010, 0x8f47001c, 
-0x24051800, 0x32c60020, 0xc002a03, 0x0, 
-0x3c030001, 0x8c633f40, 0x3c050fff, 0x34a5ffff, 
-0x3c020001, 0x8c423f44, 0x3c040800, 0x651824, 
-0x31882, 0x641825, 0x451024, 0x21082, 
-0x441025, 0xae420080, 0x32c20180, 0x10400056, 
-0xae430020, 0x8f82005c, 0x3c030080, 0x431024, 
-0x1040000d, 0x0, 0x8f820050, 0xafa20010, 
-0x8f82005c, 0x240e0001, 0x3c040001, 0x24842f68, 
-0xa3ae003f, 0xafa20014, 0x8f870040, 0x24051900, 
-0xc002a03, 0x2c03021, 0x8f820050, 0x3c030010, 
-0x431024, 0x10400016, 0x0, 0x8c020218, 
-0x30420040, 0x1040000f, 0x24020001, 0x8f820050, 
-0x8c030218, 0x240e0001, 0x3c040001, 0x24842e90, 
-0xa3ae003f, 0xafa20010, 0xafa30014, 0x8f870040, 
-0x24052000, 0xc002a03, 0x2c03021, 0x10000004, 
-0x0, 0x3c010001, 0x370821, 0xa02240f4, 
-0x3c040001, 0x24842f74, 0x3c050001, 0x24a59b2c, 
-0x3c060001, 0x24c69bac, 0xc53023, 0x8f420008, 
-0x27b30030, 0x2603821, 0x27b10034, 0x34420e00, 
-0xaf420008, 0xc001750, 0xafb10010, 0x3c040001, 
-0x24842f8c, 0x3c050001, 0x24a5d180, 0x3c060001, 
-0x24c6dc78, 0xc53023, 0x2603821, 0xaf42010c, 
-0xc001750, 0xafb10010, 0x3c040001, 0x24842fa4, 
-0x3c050001, 0x24a5e25c, 0x3c060001, 0x24c6e948, 
-0xc53023, 0x2603821, 0x3c010001, 0xac223f50, 
-0xc001750, 0xafb10010, 0x3c040001, 0x24842fbc, 
-0x10000027, 0x24052100, 0x3c040001, 0x24842fc4, 
-0x3c050001, 0x24a599e8, 0x3c060001, 0x24c69b24, 
-0xc53023, 0x27b10030, 0x2203821, 0x27b30034, 
-0xc001750, 0xafb30010, 0x3c040001, 0x24842fd4, 
-0x3c050001, 0x24a5c3f0, 0x3c060001, 0x24c6d178, 
-0xc53023, 0x2203821, 0xaf42010c, 0xc001750, 
-0xafb30010, 0x3c040001, 0x24842fe4, 0x3c050001, 
-0x24a5e0fc, 0x3c060001, 0x24c6e254, 0xc53023, 
-0x2203821, 0x3c010001, 0xac223f50, 0xc001750, 
-0xafb30010, 0x3c040001, 0x24842ff8, 0x24052150, 
-0x2c03021, 0x3821, 0x3c010001, 0xac223f5c, 
-0xafa00010, 0xc002a03, 0xafa00014, 0x3c030001, 
-0x8c633f50, 0x3c110fff, 0x3631ffff, 0x3c020001, 
-0x8c423f5c, 0x3c1e0800, 0x711824, 0x31882, 
-0x7e1825, 0x511024, 0x21082, 0x5e1025, 
-0xae430038, 0xae420078, 0x8c020218, 0x30420040, 
-0x14400004, 0x24020001, 0x3c010001, 0x370821, 
-0xa02240f4, 0x3c040001, 0x24843004, 0x3c050001, 
-0x24a5dc80, 0x3c060001, 0x24c6dddc, 0xc53023, 
-0x27b50030, 0x2a03821, 0x27b30034, 0xc001750, 
-0xafb30010, 0x3c010001, 0xac223f48, 0x511024, 
-0x21082, 0x5e1025, 0xae420050, 0x32c22000, 
-0x10400005, 0x2a03821, 0x3c020000, 0x24425b78, 
-0x1000000d, 0x511024, 0x3c040001, 0x24843018, 
-0x3c050001, 0x24a5dde4, 0x3c060001, 0x24c6df94, 
-0xc53023, 0xc001750, 0xafb30010, 0x3c010001, 
-0xac223f60, 0x511024, 0x21082, 0x5e1025, 
-0xae420048, 0x32c24000, 0x10400005, 0x27a70030, 
-0x3c020000, 0x24425b78, 0x1000000e, 0x21100, 
-0x3c040001, 0x24843030, 0x3c050001, 0x24a5df9c, 
-0x3c060001, 0x24c6e0f4, 0xc53023, 0x27a20034, 
-0xc001750, 0xafa20010, 0x3c010001, 0xac223f54, 
-0x21100, 0x21182, 0x3c030800, 0x431025, 
-0xae420060, 0x3c040001, 0x24843048, 0x3c050000, 
-0x24a57ca0, 0x3c060001, 0x24c680c4, 0xc53023, 
-0x27b10030, 0x2203821, 0x27b30034, 0xc001750, 
-0xafb30010, 0x3c1e0fff, 0x37deffff, 0x3c040001, 
-0x24843054, 0x3c050000, 0x24a56318, 0x3c060000, 
-0x24c66478, 0xc53023, 0x2203821, 0x3c010001, 
-0xac223f28, 0x5e1024, 0x21082, 0x3c150800, 
-0x551025, 0xae4200b8, 0xc001750, 0xafb30010, 
-0x3c040001, 0x24843060, 0x3c050000, 0x24a56480, 
-0x3c060000, 0x24c666f8, 0xc53023, 0x2203821, 
-0x3c010001, 0xac223f1c, 0x5e1024, 0x21082, 
-0x551025, 0xae4200e8, 0xc001750, 0xafb30010, 
-0x3c040001, 0x24843078, 0x3c050000, 0x24a56700, 
-0x3c060000, 0x24c66830, 0xc53023, 0x2203821, 
-0x3c010001, 0xac223f14, 0x5e1024, 0x21082, 
-0x551025, 0xae4200c0, 0xc001750, 0xafb30010, 
-0x3c040001, 0x24843090, 0x3c050001, 0x24a5f300, 
-0x3c060001, 0x24c6f3d8, 0xc53023, 0x2203821, 
-0x3c010001, 0xac223f20, 0x5e1024, 0x21082, 
-0x551025, 0xae4200c8, 0xc001750, 0xafb30010, 
-0x3c040001, 0x2484309c, 0x3c050001, 0x24a5c2d0, 
-0x3c060001, 0x24c6c30c, 0xc53023, 0x2203821, 
-0xaf420110, 0xc001750, 0xafb30010, 0x3c040001, 
-0x248430ac, 0x3c050001, 0x24a5c314, 0x3c060001, 
-0x24c6c33c, 0xc53023, 0x2203821, 0xaf420114, 
-0xc001750, 0xafb30010, 0x3c040001, 0x248430b8, 
-0x3c050001, 0x24a5eaa0, 0x3c060001, 0x24c6ef78, 
-0xc53023, 0x2203821, 0xaf420118, 0xc001750, 
-0xafb30010, 0x3c010001, 0xac223f64, 0x5e1024, 
-0x21082, 0x551025, 0xc003dcf, 0xae4200d0, 
-0xc003a54, 0x0, 0xc002630, 0x0, 
-0xac000228, 0xac00022c, 0x96e20450, 0x2442ffff, 
-0xaf420038, 0x96e20460, 0xaf420080, 0x32c24000, 
-0x14400003, 0x0, 0x96e20480, 0xaf420084, 
-0x96e70490, 0x50e00001, 0x24070800, 0x24e2ffff, 
-0xaf420088, 0xaf42007c, 0x24020800, 0x10e2000f, 
-0x32c24000, 0x10400003, 0x24020400, 0x10e2000b, 
-0x0, 0x240e0001, 0x3c040001, 0x248430c8, 
-0xa3ae003f, 0x96e60490, 0x24052170, 0x2c03821, 
-0xafa00010, 0xc002a03, 0xafa00014, 0x8f43012c, 
-0x8f44012c, 0x24020001, 0xa34205b3, 0xaf430094, 
-0xaf440098, 0xafa00010, 0xafa00014, 0x8f460080, 
-0x8f470084, 0x3c040001, 0x248430d4, 0xc002a03, 
-0x24052200, 0xc00232c, 0x3c110800, 0x3c1433d8, 
-0x3694cb58, 0x3c020800, 0x34420080, 0x3c040001, 
-0x248430e0, 0x3c050000, 0x24a55bbc, 0x3c060000, 
-0x24c65bd8, 0xc53023, 0x27a70030, 0xaf820060, 
-0x2402ffff, 0xaf820064, 0x27a20034, 0xc001750, 
-0xafa20010, 0x3c010001, 0xac223f04, 0x21100, 
-0x21182, 0x511025, 0xc0018a8, 0xae420000, 
-0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 
-0x3c020000, 0x24424034, 0xaf820244, 0xaf800240, 
-0x8f820060, 0x511024, 0x14400005, 0x3c030800, 
-0x8f820060, 0x431024, 0x1040fffd, 0x0, 
-0xc003a61, 0x8821, 0x3c020100, 0xafa20020, 
-0x8f530018, 0x240200ff, 0x56620001, 0x26710001, 
-0x8c020228, 0x1622000e, 0x1330c0, 0x8f42032c, 
-0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 
-0x3c040001, 0x24842da4, 0x3c050009, 0xafa00014, 
-0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 
-0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 
-0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, 
-0x1021, 0x24070004, 0xafa70010, 0xafb10014, 
-0x8f48000c, 0x24c604c0, 0x2e63021, 0xafa80018, 
-0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 
-0x822021, 0x100f809, 0x892021, 0x1440000b, 
-0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24842dac, 0x3c050009, 0xafa20014, 
-0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 
-0x8f450154, 0x8f43000c, 0xaf510018, 0x8f860120, 
-0x24020010, 0xafa20010, 0xafb10014, 0xafa30018, 
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 
-0x0, 0x8f420330, 0x24420001, 0xaf420330, 
-0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24842db4, 0x3c050009, 0xafa20014, 
-0x8fa60020, 0x34a50300, 0xc002a03, 0x2603821, 
-0x8f4202d4, 0x24420001, 0xaf4202d4, 0x8f4202d4, 
-0x93a2003f, 0x10400069, 0x3c020700, 0x34423000, 
-0xafa20028, 0x8f530018, 0x240200ff, 0x12620002, 
-0x8821, 0x26710001, 0x8c020228, 0x1622000e, 
-0x1330c0, 0x8f42032c, 0x24420001, 0xaf42032c, 
-0x8f42032c, 0x8c020228, 0x3c040001, 0x24842da4, 
-0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60028, 
-0x1000003f, 0x34a50100, 0xd71021, 0x8fa30028, 
-0x8fa4002c, 0xac4304c0, 0xac4404c4, 0xc01821, 
-0x8f440168, 0x8f45016c, 0x1021, 0x24070004, 
-0xafa70010, 0xafb10014, 0x8f48000c, 0x24c604c0, 
-0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, 
-0xa32821, 0xa3482b, 0x822021, 0x100f809, 
-0x892021, 0x1440000b, 0x24070008, 0x8f820120, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24842dac, 
-0x3c050009, 0xafa20014, 0x8fa60028, 0x1000001c, 
-0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 
-0xaf510018, 0x8f860120, 0x24020010, 0xafa20010, 
-0xafb10014, 0xafa30018, 0x8f42010c, 0x40f809, 
-0x24c6001c, 0x14400010, 0x0, 0x8f420330, 
-0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24842db4, 
-0x3c050009, 0xafa20014, 0x8fa60028, 0x34a50300, 
-0xc002a03, 0x2603821, 0x8f4202e0, 0x24420001, 
-0xaf4202e0, 0x8f4202e0, 0x3c040001, 0x248430f0, 
-0xafa00010, 0xafa00014, 0x8fa60028, 0x24052300, 
-0xc002a03, 0x3821, 0x10000004, 0x0, 
-0x8c020264, 0x10400005, 0x0, 0x8f8200a0, 
-0x30420004, 0x1440fffa, 0x0, 0x8f820044, 
-0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, 
-0xaf4202f8, 0x8f4202f8, 0x8f8200d8, 0x8f8300d4, 
-0x431023, 0x2442ff80, 0xaf420090, 0x8f420090, 
-0x2842ff81, 0x10400006, 0x24020001, 0x8f420090, 
-0x8f430138, 0x431021, 0xaf420090, 0x24020001, 
-0xaf42008c, 0x32c20008, 0x10400006, 0x0, 
-0x8f820214, 0x3c038100, 0x3042ffff, 0x431025, 
-0xaf820214, 0x3c020001, 0x8c423e24, 0x30420001, 
-0x10400009, 0x0, 0x3c040001, 0x248430fc, 
-0x3c050000, 0x24a56c40, 0x3c060000, 0x24c670e8, 
-0x10000008, 0xc53023, 0x3c040001, 0x2484310c, 
-0x3c050000, 0x24a56838, 0x3c060000, 0x24c66c38, 
-0xc53023, 0x27a70030, 0x27a20034, 0xc001750, 
-0xafa20010, 0x3c010001, 0xac223f18, 0x3c020001, 
-0x8c423f18, 0x3c030800, 0x21100, 0x21182, 
-0x431025, 0xae420040, 0x8f8200a0, 0xafa20010, 
-0x8f8200b0, 0xafa20014, 0x8f86005c, 0x8f87011c, 
-0x3c040001, 0x2484311c, 0x3c010001, 0xac363ef0, 
-0x3c010001, 0xac203ee0, 0x3c010001, 0xac3c3ed8, 
-0x3c010001, 0xac3b3f08, 0x3c010001, 0xac373f0c, 
-0x3c010001, 0xac3a3eec, 0xc002a03, 0x24052400, 
-0x8f820200, 0xafa20010, 0x8f820220, 0xafa20014, 
-0x8f860044, 0x8f870050, 0x3c040001, 0x24843128, 
-0xc002a03, 0x24052500, 0x8f830060, 0x74100b, 
-0x242000a, 0x200f821, 0x0, 0xd, 
-0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 
-0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, 
-0x27bd0060, 0x27bdffe0, 0x3c040001, 0x24843134, 
-0x24052600, 0x3021, 0x3821, 0xafbf0018, 
-0xafa00010, 0xc002a03, 0xafa00014, 0x8fbf0018, 
-0x3e00008, 0x27bd0020, 0x3e00008, 0x0, 
-0x3e00008, 0x0, 0x0, 0x0, 
-0x0, 0x0, 0x0, 0x3e00008, 
-0x0, 0x3e00008, 0x0, 0x27bdfde0, 
-0x27a50018, 0x3c04dead, 0x3484beef, 0xafbf0218, 
-0x8f820150, 0x3c03001f, 0x3463ffff, 0xafa40018, 
-0xa22823, 0xa32824, 0x8ca20000, 0x1044000a, 
-0x0, 0xafa50010, 0x8ca20000, 0xafa20014, 
-0x8f860150, 0x8f870250, 0x3c040001, 0x2484313c, 
-0xc002a03, 0x24052700, 0x8fbf0218, 0x3e00008, 
-0x27bd0220, 0x27bdffe0, 0x3c06abba, 0x34c6babe, 
-0xafb00018, 0x3c100004, 0x3c07007f, 0x34e7ffff, 
-0xafbf001c, 0x102840, 0x8e040000, 0x8ca30000, 
-0xaca00000, 0xae060000, 0x8ca20000, 0xaca30000, 
-0x10460005, 0xae040000, 0xa08021, 0xf0102b, 
-0x1040fff5, 0x102840, 0x3c040001, 0x24843148, 
-0x24052800, 0x2003021, 0x3821, 0xafa00010, 
-0xc002a03, 0xafa00014, 0x2001021, 0x8fbf001c, 
-0x8fb00018, 0x3e00008, 0x27bd0020, 0x8c020224, 
-0x3047003f, 0x10e00010, 0x803021, 0x2821, 
-0x24030020, 0xe31024, 0x10400002, 0x63042, 
-0xa62821, 0x31842, 0x1460fffb, 0xe31024, 
-0x2402f000, 0xa22824, 0x3403ffff, 0x65102b, 
-0x14400003, 0x851023, 0x10000006, 0x3c020001, 
-0x62102b, 0x14400003, 0xa01021, 0x3c02ffff, 
-0x821021, 0x3e00008, 0x0, 0x27bdffd0, 
-0xafb50028, 0x8fb50040, 0xafb20020, 0xa09021, 
-0xafb1001c, 0x24c60003, 0xafbf002c, 0xafb30024, 
-0xafb00018, 0x8ea20000, 0x2403fffc, 0xc38024, 
-0x50102b, 0x1440001b, 0xe08821, 0x8e330000, 
-0xafb00010, 0x8ea20000, 0xafa20014, 0x8e270000, 
-0x24053000, 0xc002a03, 0x2403021, 0x8e230000, 
-0x702021, 0x64102b, 0x10400007, 0x2402821, 
-0x8ca20000, 0xac620000, 0x24630004, 0x64102b, 
-0x1440fffb, 0x24a50004, 0x8ea20000, 0x501023, 
-0xaea20000, 0x8e220000, 0x501021, 0x1000000b, 
-0xae220000, 0x2402002d, 0xa0820000, 0xafb00010, 
-0x8ea20000, 0x2409821, 0xafa20014, 0x8e270000, 
-0x24053100, 0xc002a03, 0x2603021, 0x2601021, 
-0x8fbf002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0030, 
-0x27bdffe8, 0x3c1cc000, 0x3c05fffe, 0x3c030001, 
-0x8c633ed0, 0x3c040001, 0x8c843edc, 0x34a5bf08, 
-0x24021ffc, 0x3c010001, 0xac223d70, 0x3c0200c0, 
-0x3c010001, 0xac223d74, 0x3c020020, 0xafbf0010, 
-0x3c0100c0, 0xac201ffc, 0x431023, 0x441023, 
-0x245bb000, 0x365b821, 0x3c1d0001, 0x8fbd3d6c, 
-0x3a0f021, 0x3c0400c0, 0x34840200, 0x3c1a00c0, 
-0x3c0300c0, 0x346307b8, 0x24021dfc, 0x3c010001, 
-0xac223d70, 0x24021844, 0x3c010001, 0xac243d74, 
-0x3c010001, 0xac223d70, 0x3c010001, 0xac233d74, 
-0xc0017ba, 0x375a0200, 0x8fbf0010, 0x3e00008, 
-0x27bd0018, 0x27bdffc8, 0x3c040001, 0x24843154, 
-0x24053200, 0x3c020001, 0x8c423d70, 0x3c030001, 
-0x8c633d74, 0x3021, 0x3603821, 0xafbf0030, 
-0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 
-0xafa2001c, 0xafa30018, 0xafb70010, 0xc002a03, 
-0xafba0014, 0xc0018c2, 0x0, 0x8f820240, 
-0x34420004, 0xaf820240, 0x24020001, 0xaf420000, 
-0x3c020001, 0x571021, 0x904240f4, 0x10400092, 
-0x2403fffc, 0x3c100001, 0x2610a79b, 0x3c120001, 
-0x2652a374, 0x2121023, 0x438024, 0x8fa3001c, 
-0x3c040001, 0x24843160, 0x70102b, 0x1440001a, 
-0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, 
-0xafb00010, 0xafa30014, 0xc002a03, 0x2203821, 
-0x8fa30018, 0x702021, 0x64102b, 0x10400007, 
-0x2403021, 0x8cc20000, 0xac620000, 0x24630004, 
-0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, 
-0x501023, 0xafa2001c, 0x8e620000, 0x501021, 
-0x1000000a, 0xae620000, 0x2408821, 0x24053100, 
-0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021, 
-0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, 
-0x8fa3001c, 0x3c040001, 0x2484317c, 0x24120020, 
-0x3c010001, 0xac313efc, 0x2c620020, 0x1440001d, 
-0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, 
-0x24c63f90, 0xafa70010, 0xafa30014, 0xc002a03, 
-0x2003821, 0x8fa30018, 0x3c040001, 0x24843f90, 
-0x24650020, 0x65102b, 0x10400007, 0x0, 
-0x8c820000, 0xac620000, 0x24630004, 0x65102b, 
-0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, 
-0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, 
-0xae220000, 0x3c100001, 0x26103f90, 0x24053100, 
-0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, 
-0x2402002d, 0xc002a03, 0xa0820000, 0x24070020, 
-0x3c040001, 0x24843190, 0x8fa3001c, 0x24120020, 
-0x3c010001, 0xac303f30, 0x2c620020, 0x1440001d, 
-0x27b10018, 0x8fb00018, 0x24053000, 0x3c060001, 
-0x24c63fb0, 0xafa70010, 0xafa30014, 0xc002a03, 
-0x2003821, 0x8fa30018, 0x3c040001, 0x24843fb0, 
-0x24650020, 0x65102b, 0x10400007, 0x0, 
-0x8c820000, 0xac620000, 0x24630004, 0x65102b, 
-0x1440fffb, 0x24840004, 0x8fa2001c, 0x521023, 
-0xafa2001c, 0x8e220000, 0x521021, 0x1000000b, 
-0xae220000, 0x3c100001, 0x26103fb0, 0x24053100, 
-0xafa70010, 0xafa30014, 0x8fa70018, 0x2003021, 
-0x2402002d, 0xc002a03, 0xa0820000, 0x3c010001, 
-0x10000031, 0xac303f2c, 0x3c100000, 0x26107c8f, 
-0x3c120000, 0x26527b0c, 0x2121023, 0x438024, 
-0x8fa3001c, 0x3c040001, 0x248431a4, 0x70102b, 
+0x24842ed4, 0x3c050001, 0x24a52ba0, 0x3c060001, 
+0x24c62c18, 0xc53023, 0x8f420008, 0x27b30030, 
+0x2603821, 0x27b10034, 0x34420e00, 0xaf420008, 
+0xc001751, 0xafb10010, 0x3c040001, 0x24842eec, 
+0x3c050001, 0x24a5cffc, 0x3c060001, 0x24c6db04, 
+0xc53023, 0x2603821, 0xaf42010c, 0xc001751, 
+0xafb10010, 0x3c040001, 0x24842f04, 0x3c050001, 
+0x24a5df84, 0x3c060001, 0x24c6e6bc, 0xc53023, 
+0x2603821, 0x3c010001, 0xac223eb0, 0xc001751, 
+0xafb10010, 0x3c040001, 0x24842f1c, 0x10000027, 
+0x24052100, 0x3c040001, 0x24842f24, 0x3c050001, 
+0x24a599c8, 0x3c060001, 0x24c69b04, 0xc53023, 
+0x27b10030, 0x2203821, 0x27b30034, 0xc001751, 
+0xafb30010, 0x3c040001, 0x24842f34, 0x3c050001, 
+0x24a5c25c, 0x3c060001, 0x24c6cff4, 0xc53023, 
+0x2203821, 0xaf42010c, 0xc001751, 0xafb30010, 
+0x3c040001, 0x24842f44, 0x3c050001, 0x24a5de24, 
+0x3c060001, 0x24c6df7c, 0xc53023, 0x2203821, 
+0x3c010001, 0xac223eb0, 0xc001751, 0xafb30010, 
+0x3c040001, 0x24842f58, 0x24052150, 0x2c03021, 
+0x3821, 0x3c010001, 0xac223ebc, 0xafa00010, 
+0xc0029bb, 0xafa00014, 0x3c030001, 0x8c633eb0, 
+0x3c110fff, 0x3631ffff, 0x3c020001, 0x8c423ebc, 
+0x3c1e0800, 0x711824, 0x31882, 0x7e1825, 
+0x511024, 0x21082, 0x5e1025, 0xae430038, 
+0xae420078, 0x8c020218, 0x30420040, 0x14400004, 
+0x24020001, 0x3c010001, 0x370821, 0xa02240f4, 
+0x3c040001, 0x24842f64, 0x3c050001, 0x24a52ab4, 
+0x3c060001, 0x24c62b90, 0xc53023, 0x27b50030, 
+0x2a03821, 0x27b30034, 0xc001751, 0xafb30010, 
+0x3c010001, 0xac223ea8, 0x511024, 0x21082, 
+0x5e1025, 0xae420050, 0x32c22000, 0x10400005, 
+0x2a03821, 0x3c020000, 0x24425b74, 0x1000000d, 
+0x511024, 0x3c040001, 0x24842f78, 0x3c050001, 
+0x24a5db0c, 0x3c060001, 0x24c6dcbc, 0xc53023, 
+0xc001751, 0xafb30010, 0x3c010001, 0xac223ec0, 
+0x511024, 0x21082, 0x5e1025, 0xae420048, 
+0x32c24000, 0x10400005, 0x27a70030, 0x3c020000, 
+0x24425b74, 0x1000000e, 0x21100, 0x3c040001, 
+0x24842f90, 0x3c050001, 0x24a5dcc4, 0x3c060001, 
+0x24c6de1c, 0xc53023, 0x27a20034, 0xc001751, 
+0xafa20010, 0x3c010001, 0xac223eb4, 0x21100, 
+0x21182, 0x3c030800, 0x431025, 0xae420060, 
+0x3c040001, 0x24842fa8, 0x3c050000, 0x24a57c80, 
+0x3c060001, 0x24c680a4, 0xc53023, 0x27b10030, 
+0x2203821, 0x27b30034, 0xc001751, 0xafb30010, 
+0x3c1e0fff, 0x37deffff, 0x3c040001, 0x24842fb4, 
+0x3c050000, 0x24a56318, 0x3c060000, 0x24c6645c, 
+0xc53023, 0x2203821, 0x3c010001, 0xac223e88, 
+0x5e1024, 0x21082, 0x3c150800, 0x551025, 
+0xae4200b8, 0xc001751, 0xafb30010, 0x3c040001, 
+0x24842fc0, 0x3c050000, 0x24a56464, 0x3c060000, 
+0x24c666dc, 0xc53023, 0x2203821, 0x3c010001, 
+0xac223e7c, 0x5e1024, 0x21082, 0x551025, 
+0xae4200e8, 0xc001751, 0xafb30010, 0x3c040001, 
+0x24842fd8, 0x3c050000, 0x24a566e4, 0x3c060000, 
+0x24c66814, 0xc53023, 0x2203821, 0x3c010001, 
+0xac223e74, 0x5e1024, 0x21082, 0x551025, 
+0xae4200c0, 0xc001751, 0xafb30010, 0x3c040001, 
+0x24842ff0, 0x3c050001, 0x24a5efb0, 0x3c060001, 
+0x24c6f088, 0xc53023, 0x2203821, 0x3c010001, 
+0xac223e80, 0x5e1024, 0x21082, 0x551025, 
+0xae4200c8, 0xc001751, 0xafb30010, 0x3c040001, 
+0x24842ffc, 0x3c050001, 0x24a529f0, 0x3c060001, 
+0x24c62a78, 0xc53023, 0x2203821, 0xaf420110, 
+0xc001751, 0xafb30010, 0x3c040001, 0x2484300c, 
+0x3c050001, 0x24a52a80, 0x3c060001, 0x24c62aac, 
+0xc53023, 0x2203821, 0xaf420114, 0xc001751, 
+0xafb30010, 0x3c040001, 0x24843018, 0x3c050001, 
+0x24a5e820, 0x3c060001, 0x24c6ec24, 0xc53023, 
+0x2203821, 0xaf420118, 0xc001751, 0xafb30010, 
+0x3c010001, 0xac223ec4, 0x5e1024, 0x21082, 
+0x551025, 0xc003cfb, 0xae4200d0, 0xc0039b4, 
+0x0, 0xc002628, 0x0, 0xac000228, 
+0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038, 
+0x96e20460, 0xaf420080, 0x32c24000, 0x14400003, 
+0x0, 0x96e20480, 0xaf420084, 0x96e70490, 
+0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088, 
+0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000, 
+0x10400003, 0x24020400, 0x10e2000b, 0x0, 
+0x240e0001, 0x3c040001, 0x24843028, 0xa3ae003f, 
+0x96e60490, 0x24052170, 0x2c03821, 0xafa00010, 
+0xc0029bb, 0xafa00014, 0x8f43012c, 0x8f44012c, 
+0x24020001, 0xa34205b3, 0xaf430094, 0xaf440098, 
+0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084, 
+0x3c040001, 0x24843034, 0xc0029bb, 0x24052200, 
+0xc002324, 0x3c110800, 0x3c1433d8, 0x3694cb58, 
+0x3c020800, 0x34420080, 0x3c040001, 0x24843040, 
+0x3c050000, 0x24a55bb8, 0x3c060000, 0x24c65bd4, 
+0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff, 
+0xaf820064, 0x27a20034, 0xc001751, 0xafa20010, 
+0x3c010001, 0xac223e64, 0x21100, 0x21182, 
+0x511025, 0xc0018a8, 0xae420000, 0x8f820240, 
+0x3c030001, 0x431025, 0xaf820240, 0x3c020000, 
+0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, 
+0x511024, 0x14400005, 0x3c030800, 0x8f820060, 
+0x431024, 0x1040fffd, 0x0, 0xc0039c1, 
+0x8821, 0x3c020100, 0xafa20020, 0x8f530018, 
+0x240200ff, 0x56620001, 0x26710001, 0x8c020228, 
+0x1622000e, 0x1330c0, 0x8f42032c, 0x24420001, 
+0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, 
+0x24842d04, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
+0xc01821, 0x8f440168, 0x8f45016c, 0x1021, 
+0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c, 
+0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c, 
+0x24070008, 0xa32821, 0xa3482b, 0x822021, 
+0x100f809, 0x892021, 0x1440000b, 0x24070008, 
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, 
+0x24842d0c, 0x3c050009, 0xafa20014, 0x8fa60020, 
+0x1000001c, 0x34a50200, 0x8f440150, 0x8f450154, 
+0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, 
+0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, 
+0x40f809, 0x24c6001c, 0x14400010, 0x0, 
+0x8f420330, 0x24420001, 0xaf420330, 0x8f420330, 
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, 
+0x24842d14, 0x3c050009, 0xafa20014, 0x8fa60020, 
+0x34a50300, 0xc0029bb, 0x2603821, 0x8f4202d4, 
+0x24420001, 0xaf4202d4, 0x8f4202d4, 0x93a2003f, 
+0x10400069, 0x3c020700, 0x34423000, 0xafa20028, 
+0x8f530018, 0x240200ff, 0x12620002, 0x8821, 
+0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, 
+0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 
+0x8c020228, 0x3c040001, 0x24842d04, 0x3c050009, 
+0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f, 
+0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c, 
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 
+0x8f45016c, 0x1021, 0x24070004, 0xafa70010, 
+0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021, 
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
+0xa3482b, 0x822021, 0x100f809, 0x892021, 
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 
+0x8f820124, 0x3c040001, 0x24842d0c, 0x3c050009, 
+0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200, 
+0x8f440150, 0x8f450154, 0x8f43000c, 0xaf510018, 
+0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, 
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 
+0x14400010, 0x0, 0x8f420330, 0x24420001, 
+0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 
+0x8f820124, 0x3c040001, 0x24842d14, 0x3c050009, 
+0xafa20014, 0x8fa60028, 0x34a50300, 0xc0029bb, 
+0x2603821, 0x8f4202e0, 0x24420001, 0xaf4202e0, 
+0x8f4202e0, 0x3c040001, 0x24843050, 0xafa00010, 
+0xafa00014, 0x8fa60028, 0x24052300, 0xc0029bb, 
+0x3821, 0x10000004, 0x0, 0x8c020264, 
+0x10400005, 0x0, 0x8f8200a0, 0x30420004, 
+0x1440fffa, 0x0, 0x8f820044, 0x34420004, 
+0xaf820044, 0x8f4202f8, 0x24420001, 0xaf4202f8, 
+0x8f4202f8, 0x8f8200d8, 0x8f8300d4, 0x431023, 
+0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81, 
+0x10400006, 0x24020001, 0x8f420090, 0x8f430138, 
+0x431021, 0xaf420090, 0x24020001, 0xaf42008c, 
+0x32c20008, 0x10400006, 0x0, 0x8f820214, 
+0x3c038100, 0x3042ffff, 0x431025, 0xaf820214, 
+0x3c020001, 0x8c423d84, 0x30420001, 0x10400009, 
+0x0, 0x3c040001, 0x2484305c, 0x3c050000, 
+0x24a56c24, 0x3c060000, 0x24c670cc, 0x10000008, 
+0xc53023, 0x3c040001, 0x2484306c, 0x3c050000, 
+0x24a5681c, 0x3c060000, 0x24c66c1c, 0xc53023, 
+0x27a70030, 0x27a20034, 0xc001751, 0xafa20010, 
+0x3c010001, 0xac223e78, 0x3c020001, 0x8c423e78, 
+0x3c030800, 0x21100, 0x21182, 0x431025, 
+0xae420040, 0x8f8200a0, 0xafa20010, 0x8f8200b0, 
+0xafa20014, 0x8f86005c, 0x8f87011c, 0x3c040001, 
+0x2484307c, 0x3c010001, 0xac363e50, 0x3c010001, 
+0xac203e40, 0x3c010001, 0xac3c3e38, 0x3c010001, 
+0xac3b3e68, 0x3c010001, 0xac373e6c, 0x3c010001, 
+0xac3a3e4c, 0xc0029bb, 0x24052400, 0x8f820200, 
+0xafa20010, 0x8f820220, 0xafa20014, 0x8f860044, 
+0x8f870050, 0x3c040001, 0x24843088, 0xc0029bb, 
+0x24052500, 0x8f830060, 0x74100b, 0x242000a, 
+0x200f821, 0x0, 0xd, 0x8fbf0058, 
+0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 
+0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 
+0x27bdffe0, 0x3c040001, 0x24843094, 0x24052600, 
+0x3021, 0x3821, 0xafbf0018, 0xafa00010, 
+0xc0029bb, 0xafa00014, 0x8fbf0018, 0x3e00008, 
+0x27bd0020, 0x3e00008, 0x0, 0x3e00008, 
+0x0, 0x0, 0x0, 0x0, 
+0x0, 0x0, 0x3e00008, 0x0, 
+0x3e00008, 0x0, 0x27bdfde0, 0x27a50018, 
+0x3c04dead, 0x3484beef, 0xafbf0218, 0x8f820150, 
+0x3c03001f, 0x3463ffff, 0xafa40018, 0xa22823, 
+0xa32824, 0x8ca20000, 0x1044000a, 0x0, 
+0xafa50010, 0x8ca20000, 0xafa20014, 0x8f860150, 
+0x8f870250, 0x3c040001, 0x2484309c, 0xc0029bb, 
+0x24052700, 0x8fbf0218, 0x3e00008, 0x27bd0220, 
+0x27bdffe0, 0x3c06abba, 0x34c6babe, 0xafb00018, 
+0x3c100004, 0x3c07007f, 0x34e7ffff, 0xafbf001c, 
+0x102840, 0x8e040000, 0x8ca30000, 0xaca00000, 
+0xae060000, 0x8ca20000, 0xaca30000, 0x10460005, 
+0xae040000, 0xa08021, 0xf0102b, 0x1040fff5, 
+0x102840, 0x3c040001, 0x248430a8, 0x24052800, 
+0x2003021, 0x3821, 0xafa00010, 0xc0029bb, 
+0xafa00014, 0x2001021, 0x8fbf001c, 0x8fb00018, 
+0x3e00008, 0x27bd0020, 0x8c020224, 0x3047003f, 
+0x10e00010, 0x803021, 0x2821, 0x24030020, 
+0xe31024, 0x10400002, 0x63042, 0xa62821, 
+0x31842, 0x1460fffb, 0xe31024, 0x2402f000, 
+0xa22824, 0x3402ffff, 0x45102b, 0x14400003, 
+0x3c020001, 0x10000008, 0x3c020001, 0x3442ffff, 
+0x851823, 0x43102b, 0x14400003, 0xa01021, 
+0x3c02fffe, 0x821021, 0x3e00008, 0x0, 
+0x27bdffd0, 0xafb50028, 0x8fb50040, 0xafb20020, 
+0xa09021, 0xafb1001c, 0x24c60003, 0xafbf002c, 
+0xafb30024, 0xafb00018, 0x8ea20000, 0x2403fffc, 
+0xc38024, 0x50102b, 0x1440001b, 0xe08821, 
+0x8e330000, 0xafb00010, 0x8ea20000, 0xafa20014, 
+0x8e270000, 0x24053000, 0xc0029bb, 0x2403021, 
+0x8e230000, 0x702021, 0x64102b, 0x10400007, 
+0x2402821, 0x8ca20000, 0xac620000, 0x24630004, 
+0x64102b, 0x1440fffb, 0x24a50004, 0x8ea20000, 
+0x501023, 0xaea20000, 0x8e220000, 0x501021, 
+0x1000000b, 0xae220000, 0x2402002d, 0xa0820000, 
+0xafb00010, 0x8ea20000, 0x2409821, 0xafa20014, 
+0x8e270000, 0x24053100, 0xc0029bb, 0x2603021, 
+0x2601021, 0x8fbf002c, 0x8fb50028, 0x8fb30024, 
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 
+0x27bd0030, 0x27bdffe8, 0x3c1cc000, 0x3c05fffe, 
+0x3c030001, 0x8c633e30, 0x3c040001, 0x8c843e3c, 
+0x34a5bf08, 0x24021ffc, 0x3c010001, 0xac223cd0, 
+0x3c0200c0, 0x3c010001, 0xac223cd4, 0x3c020020, 
+0xafbf0010, 0x3c0100c0, 0xac201ffc, 0x431023, 
+0x441023, 0x245bb000, 0x365b821, 0x3c1d0001, 
+0x8fbd3ccc, 0x3a0f021, 0x3c0400c0, 0x34840200, 
+0x3c1a00c0, 0x3c0300c0, 0x346307b8, 0x24021dfc, 
+0x3c010001, 0xac223cd0, 0x24021844, 0x3c010001, 
+0xac243cd4, 0x3c010001, 0xac223cd0, 0x3c010001, 
+0xac233cd4, 0xc0017bb, 0x375a0200, 0x8fbf0010, 
+0x3e00008, 0x27bd0018, 0x27bdffc8, 0x3c040001, 
+0x248430b4, 0x24053200, 0x3c020001, 0x8c423cd0, 
+0x3c030001, 0x8c633cd4, 0x3021, 0x3603821, 
+0xafbf0030, 0xafb3002c, 0xafb20028, 0xafb10024, 
+0xafb00020, 0xafa2001c, 0xafa30018, 0xafb70010, 
+0xc0029bb, 0xafba0014, 0xc0018c2, 0x0, 
+0x8f820240, 0x34420004, 0xaf820240, 0x24020001, 
+0xaf420000, 0x3c020001, 0x571021, 0x904240f4, 
+0x10400092, 0x2403fffc, 0x3c100001, 0x2610a673, 
+0x3c120001, 0x2652a24c, 0x2121023, 0x438024, 
+0x8fa3001c, 0x3c040001, 0x248430c0, 0x70102b, 
 0x1440001a, 0x27b30018, 0x8fb10018, 0x24053000, 
-0x2403021, 0xafb00010, 0xafa30014, 0xc002a03, 
+0x2403021, 0xafb00010, 0xafa30014, 0xc0029bb, 
 0x2203821, 0x8fa30018, 0x702021, 0x64102b, 
 0x10400007, 0x2403021, 0x8cc20000, 0xac620000, 
 0x24630004, 0x64102b, 0x1440fffb, 0x24c60004, 
 0x8fa2001c, 0x501023, 0xafa2001c, 0x8e620000, 
 0x501021, 0x1000000a, 0xae620000, 0x2408821, 
 0x24053100, 0xafb00010, 0xafa30014, 0x8fa70018, 
-0x2203021, 0x2402002d, 0xc002a03, 0xa0820000, 
-0x3c010001, 0xac313efc, 0x3c030001, 0x8c633efc, 
-0x24020400, 0x60f809, 0xaf820070, 0x8fbf0030, 
-0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 
-0x3e00008, 0x27bd0038, 0x0, 0x8f820040, 
+0x2203021, 0x2402002d, 0xc0029bb, 0xa0820000, 
+0x24070020, 0x8fa3001c, 0x3c040001, 0x248430dc, 
+0x24120020, 0x3c010001, 0xac313e5c, 0x2c620020, 
+0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, 
+0x3c060001, 0x24c63ef0, 0xafa70010, 0xafa30014, 
+0xc0029bb, 0x2003821, 0x8fa30018, 0x3c040001, 
+0x24843ef0, 0x24650020, 0x65102b, 0x10400007, 
+0x0, 0x8c820000, 0xac620000, 0x24630004, 
+0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, 
+0x521023, 0xafa2001c, 0x8e220000, 0x521021, 
+0x1000000b, 0xae220000, 0x3c100001, 0x26103ef0, 
+0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, 
+0x2003021, 0x2402002d, 0xc0029bb, 0xa0820000, 
+0x24070020, 0x3c040001, 0x248430f0, 0x8fa3001c, 
+0x24120020, 0x3c010001, 0xac303e90, 0x2c620020, 
+0x1440001d, 0x27b10018, 0x8fb00018, 0x24053000, 
+0x3c060001, 0x24c63f10, 0xafa70010, 0xafa30014, 
+0xc0029bb, 0x2003821, 0x8fa30018, 0x3c040001, 
+0x24843f10, 0x24650020, 0x65102b, 0x10400007, 
+0x0, 0x8c820000, 0xac620000, 0x24630004, 
+0x65102b, 0x1440fffb, 0x24840004, 0x8fa2001c, 
+0x521023, 0xafa2001c, 0x8e220000, 0x521021, 
+0x1000000b, 0xae220000, 0x3c100001, 0x26103f10, 
+0x24053100, 0xafa70010, 0xafa30014, 0x8fa70018, 
+0x2003021, 0x2402002d, 0xc0029bb, 0xa0820000, 
+0x3c010001, 0x10000031, 0xac303e8c, 0x3c100000, 
+0x26107c73, 0x3c120000, 0x26527af0, 0x2121023, 
+0x438024, 0x8fa3001c, 0x3c040001, 0x24843104, 
+0x70102b, 0x1440001a, 0x27b30018, 0x8fb10018, 
+0x24053000, 0x2403021, 0xafb00010, 0xafa30014, 
+0xc0029bb, 0x2203821, 0x8fa30018, 0x702021, 
+0x64102b, 0x10400007, 0x2403021, 0x8cc20000, 
+0xac620000, 0x24630004, 0x64102b, 0x1440fffb, 
+0x24c60004, 0x8fa2001c, 0x501023, 0xafa2001c, 
+0x8e620000, 0x501021, 0x1000000a, 0xae620000, 
+0x2408821, 0x24053100, 0xafb00010, 0xafa30014, 
+0x8fa70018, 0x2203021, 0x2402002d, 0xc0029bb, 
+0xa0820000, 0x3c010001, 0xac313e5c, 0x3c030001, 
+0x8c633e5c, 0x24020400, 0x60f809, 0xaf820070, 
+0x8fbf0030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 
+0x8fb00020, 0x3e00008, 0x27bd0038, 0x8f820040, 
 0x3c03f000, 0x431024, 0x3c036000, 0x14430006, 
 0x0, 0x8f820050, 0x2403ff80, 0x431024, 
 0x34420055, 0xaf820050, 0x8f820054, 0x244203e8, 
@@ -5033,164 +5043,274 @@
 0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, 
 0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, 
 0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, 
-0x36940040, 0x3c020001, 0x8c423e38, 0x10400027, 
-0x0, 0x3c020001, 0x8c423e24, 0x30420001, 
-0x14400010, 0x0, 0x3c020001, 0x8c423f68, 
-0x1040000c, 0x0, 0x3c020001, 0x8c423eb4, 
-0x14400008, 0x0, 0x8f830224, 0x3c020001, 
-0x8c42602c, 0x10620003, 0x0, 0xc003be0, 
-0x0, 0x934205b1, 0x10400012, 0x24020001, 
-0x934305b1, 0x14620004, 0x3c0208ff, 0x24020002, 
-0x1000000c, 0xa34205b1, 0x3442fffb, 0xa34005b1, 
-0x8f830220, 0x3c040200, 0x284a025, 0x621824, 
-0xaf830220, 0x10000004, 0x3c020200, 0xc003f57, 
-0x0, 0x3c020200, 0x2c21024, 0x10400003, 
-0x0, 0xc001de7, 0x0, 0x8f4200d8, 
-0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, 
-0x14400003, 0x0, 0xaf4000d8, 0x36940080, 
-0x8c030238, 0x1060000c, 0x0, 0x8f4201a0, 
-0x244203e8, 0xaf4201a0, 0x43102b, 0x14400006, 
-0x0, 0x934205b6, 0x14400003, 0x0, 
-0xc001c3c, 0x0, 0x8fbf0010, 0x3e00008, 
-0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8, 
-0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059, 
-0x0, 0x3c020001, 0x571021, 0x904240f0, 
-0x10400026, 0x24070008, 0x8f440160, 0x8f450164, 
-0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, 
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
-0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, 
-0x8f820128, 0x3c040001, 0x24843248, 0xafa20014, 
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 
-0x34a50900, 0x1000005c, 0x0, 0x8f4202f0, 
-0x24420001, 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 
-0xa34005b2, 0x10000027, 0xaf420038, 0x8f440160, 
-0x8f450164, 0x8f43002c, 0x8f48000c, 0x8f860120, 
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 
-0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, 
-0x24843254, 0xafa20014, 0x8f46002c, 0x8f870120, 
-0x3c050009, 0xc002a03, 0x34a51100, 0x10000036, 
-0x0, 0x8f4202f0, 0x8f43002c, 0x24420001, 
-0xaf4202f0, 0x8f4202f0, 0x24020001, 0xa34205b2, 
-0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, 
-0x3c010001, 0x370821, 0xa02040f0, 0x10000026, 
-0xaf400034, 0x934205b2, 0x1040001d, 0x0, 
-0xa34005b2, 0x8f820040, 0x30420001, 0x14400008, 
-0x2021, 0x8c030104, 0x24020001, 0x50620005, 
-0x24040001, 0x8c020264, 0x10400003, 0x801021, 
-0x24040001, 0x801021, 0x10400006, 0x0, 
-0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, 
-0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, 
-0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, 
-0x3c010001, 0x370821, 0xa02040f0, 0x3c010001, 
-0x370821, 0xa02040f1, 0x8f420000, 0x10400007, 
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, 
-0x0, 0x10000005, 0x0, 0xaf800048, 
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 
-0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060, 
-0x8f420000, 0x10400003, 0x0, 0x10000002, 
-0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008, 
-0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, 
-0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029, 
-0x24070008, 0x8f440158, 0x8f45015c, 0x8f48000c, 
-0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, 
+0x36940040, 0x3c020001, 0x8c423d98, 0x10400020, 
+0x3c020200, 0x934305b1, 0x10600007, 0x282a025, 
+0xa34005b1, 0x8f820220, 0x3c0308ff, 0x3463fffb, 
+0x431024, 0xaf820220, 0x3c020001, 0x8c423ec8, 
+0x10400016, 0x3c020200, 0x3c020001, 0x8c423e14, 
+0x14400012, 0x3c020200, 0x3c020001, 0x8c423d84, 
+0x30420001, 0x1440000d, 0x3c020200, 0x8f830224, 
+0x3c020001, 0x8c425f8c, 0x10620008, 0x3c020200, 
+0xc003b0b, 0x0, 0x10000004, 0x3c020200, 
+0xc003e84, 0x0, 0x3c020200, 0x2c21024, 
+0x10400003, 0x0, 0xc001de0, 0x0, 
+0x8f4200d8, 0x8f4300dc, 0x24420001, 0xaf4200d8, 
+0x43102b, 0x14400003, 0x0, 0xaf4000d8, 
+0x36940080, 0x8c030238, 0x1060000c, 0x0, 
+0x8f4201a0, 0x244203e8, 0xaf4201a0, 0x43102b, 
+0x14400006, 0x0, 0x934205b6, 0x14400003, 
+0x0, 0xc001c35, 0x0, 0x8fbf0010, 
+0x3e00008, 0x27bd0018, 0x3e00008, 0x0, 
+0x27bdffd8, 0xafbf0020, 0x8f43002c, 0x8f420038, 
+0x10620059, 0x0, 0x3c020001, 0x571021, 
+0x904240f0, 0x10400026, 0x24070008, 0x8f440160, 
+0x8f450164, 0x8f48000c, 0x8f860120, 0x24020020, 
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 
+0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 
+0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 
+0xafa20010, 0x8f820128, 0x3c040001, 0x248431a8, 
+0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009, 
+0xc0029bb, 0x34a50900, 0x1000005c, 0x0, 
+0x8f4202f0, 0x24420001, 0xaf4202f0, 0x8f4202f0, 
+0x8f42002c, 0xa34005b2, 0x10000027, 0xaf420038, 
+0x8f440160, 0x8f450164, 0x8f43002c, 0x8f48000c, 
+0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 
 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x14400011, 0x24020001, 0x3c010001, 0x370821, 
-0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, 
-0x3c040001, 0x2484325c, 0xafa20014, 0x8f460044, 
-0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, 
-0x1000000f, 0x0, 0x8f4202f4, 0x24420001, 
-0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, 
-0x3c010001, 0x370821, 0xa02040f2, 0x10000004, 
-0xaf400078, 0x3c010001, 0x370821, 0xa02040f2, 
-0x8f420000, 0x10400007, 0x0, 0xaf80004c, 
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 
-0x0, 0x8f820060, 0x3c03feff, 0x3463ffff, 
-0x431024, 0xaf820060, 0x8f420000, 0x10400003, 
-0x0, 0x10000002, 0xaf80004c, 0xaf800048, 
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, 
-0x0, 0x3c020001, 0x8c423e38, 0x27bdffa8, 
-0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 
-0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, 
-0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, 
-0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, 
-0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, 
-0x8c633e28, 0x34420002, 0xaf420004, 0x24020001, 
-0x14620003, 0x3c020600, 0x10000002, 0x34423000, 
-0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, 
-0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, 
-0x11420002, 0x1821, 0x25430001, 0x8c020228, 
-0x609821, 0x1662000e, 0x3c050009, 0x8f42032c, 
-0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 
-0x8fa70034, 0x3c040001, 0x2484322c, 0xafa00014, 
-0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, 
-0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, 
-0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 
+0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128, 
+0x3c040001, 0x248431b4, 0xafa20014, 0x8f46002c, 
+0x8f870120, 0x3c050009, 0xc0029bb, 0x34a51100, 
+0x10000036, 0x0, 0x8f4202f0, 0x8f43002c, 
+0x24420001, 0xaf4202f0, 0x8f4202f0, 0x24020001, 
+0xa34205b2, 0xaf430038, 0x3c010001, 0x370821, 
+0xa02040f1, 0x3c010001, 0x370821, 0xa02040f0, 
+0x10000026, 0xaf400034, 0x934205b2, 0x1040001d, 
+0x0, 0xa34005b2, 0x8f820040, 0x30420001, 
+0x14400008, 0x2021, 0x8c030104, 0x24020001, 
+0x50620005, 0x24040001, 0x8c020264, 0x10400003, 
+0x801021, 0x24040001, 0x801021, 0x10400006, 
+0x0, 0x8f4202fc, 0x24420001, 0xaf4202fc, 
+0x10000008, 0x8f4202fc, 0x8f820044, 0x34420004, 
+0xaf820044, 0x8f4202f8, 0x24420001, 0xaf4202f8, 
+0x8f4202f8, 0x3c010001, 0x370821, 0xa02040f0, 
+0x3c010001, 0x370821, 0xa02040f1, 0x8f420000, 
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 
+0x1040fffd, 0x0, 0x10000005, 0x0, 
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 
+0x8f820060, 0x3c03ff7f, 0x3463ffff, 0x431024, 
+0xaf820060, 0x8f420000, 0x10400003, 0x0, 
+0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0020, 
+0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 
+0x27bdffd8, 0xafbf0020, 0x8f430044, 0x8f42007c, 
+0x10620029, 0x24070008, 0x8f440158, 0x8f45015c, 
+0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010, 
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
+0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
+0x370821, 0xa02240f2, 0x8f820124, 0xafa20010, 
+0x8f820128, 0x3c040001, 0x248431bc, 0xafa20014, 
+0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb, 
+0x34a51300, 0x1000000f, 0x0, 0x8f4202f4, 
+0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 
+0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 
+0x10000004, 0xaf400078, 0x3c010001, 0x370821, 
+0xa02040f2, 0x8f420000, 0x10400007, 0x0, 
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 
+0x10000005, 0x0, 0xaf800048, 0x8f820048, 
+0x1040fffd, 0x0, 0x8f820060, 0x3c03feff, 
+0x3463ffff, 0x431024, 0xaf820060, 0x8f420000, 
+0x10400003, 0x0, 0x10000002, 0xaf80004c, 
+0xaf800048, 0x8fbf0020, 0x3e00008, 0x27bd0028, 
+0x3e00008, 0x0, 0x3c020001, 0x8c423d98, 
+0x27bdffa8, 0xafbf0050, 0xafbe004c, 0xafb50048, 
+0xafb30044, 0xafb20040, 0xafb1003c, 0xafb00038, 
+0x104000d5, 0x8f900044, 0x8f4200d0, 0x24430001, 
+0x2842000b, 0x144000e4, 0xaf4300d0, 0x8f420004, 
+0x30420002, 0x1440009c, 0xaf4000d0, 0x8f420004, 
+0x3c030001, 0x8c633d88, 0x34420002, 0xaf420004, 
+0x24020001, 0x14620003, 0x3c020600, 0x10000002, 
+0x34423000, 0x34421000, 0xafa20020, 0x8f4a0018, 
+0xafaa0034, 0x27aa0020, 0xafaa002c, 0x8faa0034, 
+0x240200ff, 0x11420002, 0x1821, 0x25430001, 
+0x8c020228, 0x609821, 0x1662000e, 0x3c050009, 
+0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 
+0x8c020228, 0x8fa70034, 0x3c040001, 0x2484318c, 
+0xafa00014, 0xafa20010, 0x8fa60020, 0x10000070, 
+0x34a50500, 0x8faa0034, 0xa38c0, 0xf71021, 
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
+0x8f830054, 0x8f820054, 0x247103e8, 0x2221023, 
+0x2c4203e9, 0x1040001b, 0xa821, 0xe09021, 
+0x265e04c0, 0x8f440168, 0x8f45016c, 0x2401821, 
+0x240a0004, 0xafaa0010, 0xafb30014, 0x8f48000c, 
+0x1021, 0x2fe3021, 0xafa80018, 0x8f48010c, 
+0x24070008, 0xa32821, 0xa3482b, 0x822021, 
+0x100f809, 0x892021, 0x54400006, 0x24150001, 
+0x8f820054, 0x2221023, 0x2c4203e9, 0x1440ffe9, 
+0x0, 0x32a200ff, 0x54400018, 0xaf530018, 
+0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 
+0x8f820120, 0x8faa002c, 0x8fa70034, 0xafa20010, 
+0x8f820124, 0x3c040001, 0x24843198, 0xafa20014, 
+0x8d460000, 0x3c050009, 0x10000035, 0x34a50600, 
+0x8f4202f8, 0x24150001, 0x24420001, 0xaf4202f8, 
+0x8f4202f8, 0x1000001e, 0x32a200ff, 0x8f830054, 
 0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, 
-0x1040001b, 0xa821, 0xe09021, 0x265e04c0, 
-0x8f440168, 0x8f45016c, 0x2401821, 0x240a0004, 
-0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021, 
-0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008, 
-0xa32821, 0xa3482b, 0x822021, 0x100f809, 
-0x892021, 0x54400006, 0x24150001, 0x8f820054, 
-0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0, 
-0x32a200ff, 0x54400018, 0xaf530018, 0x8f420368, 
+0x10400016, 0xa821, 0x3c1e0020, 0x24120010, 
+0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120, 
+0xafb20010, 0xafb30014, 0x5e1025, 0xafa20018, 
+0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, 
+0x1440ffe3, 0x0, 0x8f820054, 0x2221023, 
+0x2c4203e9, 0x1440ffee, 0x0, 0x32a200ff, 
+0x14400011, 0x3c050009, 0x8f420368, 0x24420001, 
+0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 
+0x8fa70034, 0xafa20010, 0x8f820124, 0x3c040001, 
+0x248431a0, 0xafa20014, 0x8d460000, 0x34a50700, 
+0xc0029bb, 0x0, 0x8f4202dc, 0x24420001, 
+0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, 
+0x50400029, 0x36100040, 0x3c020400, 0x2c21024, 
+0x10400013, 0x2404ffdf, 0x8f420240, 0x8f430244, 
+0x8f4401a4, 0x14640006, 0x36100040, 0x8f420260, 
+0x8f430264, 0x8f4401a8, 0x10640007, 0x2402ffdf, 
+0x8f420240, 0x8f430244, 0x8f440260, 0x8f450264, 
+0x10000012, 0x3a100020, 0x1000002b, 0x2028024, 
+0x8f420240, 0x8f430244, 0x8f4501a4, 0x14650006, 
+0x2048024, 0x8f420260, 0x8f430264, 0x8f4401a8, 
+0x50640021, 0x36100040, 0x8f420240, 0x8f430244, 
+0x8f440260, 0x8f450264, 0x3a100040, 0xaf4301a4, 
+0x10000019, 0xaf4501a8, 0x8f4200d4, 0x24430001, 
+0x10000011, 0x28420033, 0x8f420004, 0x30420001, 
+0x10400009, 0x3c020400, 0x2c21024, 0x10400004, 
+0x2402ffdf, 0x2028024, 0x1000000b, 0x36100040, 
+0x10000009, 0x36100060, 0x8f4200d4, 0x36100040, 
+0x24430001, 0x284201f5, 0x14400003, 0xaf4300d4, 
+0xaf4000d4, 0x3a100020, 0xaf900044, 0x2402ff7f, 
+0x282a024, 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 
+0x8fb30044, 0x8fb20040, 0x8fb1003c, 0x8fb00038, 
+0x3e00008, 0x27bd0058, 0x3e00008, 0x0, 
+0x3c020001, 0x8c423d98, 0x27bdffb0, 0xafbf0048, 
+0xafbe0044, 0xafb50040, 0xafb3003c, 0xafb20038, 
+0xafb10034, 0x104000de, 0xafb00030, 0x8f4200d0, 
+0x3c040001, 0x8c843d88, 0x24430001, 0x2842000b, 
+0xaf4400e8, 0x144000fe, 0xaf4300d0, 0x8f420004, 
+0x30420002, 0x14400095, 0xaf4000d0, 0x8f420004, 
+0x34420002, 0xaf420004, 0x24020001, 0x14820003, 
+0x3c020600, 0x10000002, 0x34423000, 0x34421000, 
+0xafa20020, 0x1821, 0x8f5e0018, 0x27aa0020, 
+0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 
+0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 
+0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 
+0x8c020228, 0x3c040001, 0x2484318c, 0x3c050009, 
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, 
+0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 
+0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 
+0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, 
+0x9821, 0xe08821, 0x263504c0, 0x8f440168, 
+0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010, 
+0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, 
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
+0xa3482b, 0x822021, 0x100f809, 0x892021, 
+0x54400006, 0x24130001, 0x8f820054, 0x2021023, 
+0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 
+0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 
+0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x24843198, 
+0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, 
+0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 
+0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff, 
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
+0x2c4203e9, 0x10400016, 0x9821, 0x3c150020, 
+0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154, 
+0x8f860120, 0xafb10010, 0xafb20014, 0x551025, 
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, 
+0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054, 
+0x2021023, 0x2c4203e9, 0x1440ffee, 0x0, 
+0x326200ff, 0x14400011, 0x0, 0x8f420368, 
 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 
-0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24843238, 0xafa20014, 0x8d460000, 
-0x3c050009, 0x10000035, 0x34a50600, 0x8f4202f8, 
-0x24150001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 
-0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, 
-0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016, 
-0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c, 
-0x8f440150, 0x8f450154, 0x8f860120, 0xafb20010, 
-0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c, 
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, 
-0x0, 0x8f820054, 0x2221023, 0x2c4203e9, 
-0x1440ffee, 0x0, 0x32a200ff, 0x14400011, 
-0x3c050009, 0x8f420368, 0x24420001, 0xaf420368, 
-0x8f420368, 0x8f820120, 0x8faa002c, 0x8fa70034, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, 
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, 
-0x0, 0x8f4202dc, 0x24420001, 0xaf4202dc, 
-0x8f4202dc, 0x8f420004, 0x30420001, 0x50400029, 
-0x36100040, 0x3c020400, 0x2c21024, 0x10400013, 
-0x2404ffdf, 0x8f420240, 0x8f430244, 0x8f4401a4, 
-0x14640006, 0x36100040, 0x8f420260, 0x8f430264, 
-0x8f4401a8, 0x10640007, 0x2402ffdf, 0x8f420240, 
-0x8f430244, 0x8f440260, 0x8f450264, 0x10000012, 
-0x3a100020, 0x1000002b, 0x2028024, 0x8f420240, 
-0x8f430244, 0x8f4501a4, 0x14650006, 0x2048024, 
-0x8f420260, 0x8f430264, 0x8f4401a8, 0x50640021, 
-0x36100040, 0x8f420240, 0x8f430244, 0x8f440260, 
-0x8f450264, 0x3a100040, 0xaf4301a4, 0x10000019, 
-0xaf4501a8, 0x8f4200d4, 0x24430001, 0x10000011, 
-0x28420033, 0x8f420004, 0x30420001, 0x10400009, 
-0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf, 
-0x2028024, 0x1000000b, 0x36100040, 0x10000009, 
-0x36100060, 0x8f4200d4, 0x36100040, 0x24430001, 
-0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4, 
-0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024, 
-0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 
-0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, 
-0x27bd0058, 0x3e00008, 0x0, 0x3c020001, 
-0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 
-0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, 
-0x8c843e28, 0x24430001, 0x2842000b, 0xaf4400e8, 
-0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, 
-0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, 
-0xaf420004, 0x24020001, 0x14820003, 0x3c020600, 
-0x10000002, 0x34423000, 0x34421000, 0xafa20020, 
+0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, 
+0x248431a0, 0x3c050009, 0xafa20014, 0x8d460000, 
+0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202dc, 
+0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8f420004, 
+0x30420001, 0x10400033, 0x3c020400, 0x2c21024, 
+0x10400017, 0x0, 0x934205b0, 0x8f440240, 
+0x8f450244, 0x8f4301a4, 0x34420020, 0x14a30006, 
+0xa34205b0, 0x8f420260, 0x8f430264, 0x8f4401a8, 
+0x10640008, 0x0, 0x8f420240, 0x8f430244, 
+0x934405b0, 0x8f460260, 0x8f470264, 0x10000016, 
+0x38840040, 0x934205b0, 0x10000048, 0x304200bf, 
+0x934205b0, 0x8f440240, 0x8f450244, 0x8f4301a4, 
+0x304200bf, 0x14a30006, 0xa34205b0, 0x8f420260, 
+0x8f430264, 0x8f4401a8, 0x1064000b, 0x0, 
+0x8f420240, 0x8f430244, 0x934405b0, 0x8f460260, 
+0x8f470264, 0x38840020, 0xaf4301a4, 0xaf4701a8, 
+0x10000033, 0xa34405b0, 0x934205b0, 0x1000002f, 
+0x34420020, 0x934205b0, 0x8f4300d4, 0x34420020, 
+0xa34205b0, 0x24620001, 0x10000023, 0x28630033, 
+0x8f4200e4, 0x8f4300e0, 0x24420001, 0xaf4200e4, 
+0x43102a, 0x14400006, 0x24030001, 0x8f4200e8, 
+0x14430002, 0xaf4000e4, 0x24030004, 0xaf4300e8, 
+0x8f420004, 0x30420001, 0x1040000d, 0x3c020400, 
+0x2c21024, 0x10400007, 0x0, 0x934205b0, 
+0x34420040, 0xa34205b0, 0x934205b0, 0x1000000f, 
+0x304200df, 0x934205b0, 0x1000000c, 0x34420060, 
+0x934205b0, 0x8f4300d4, 0x34420020, 0xa34205b0, 
+0x24620001, 0x286300fb, 0x14600005, 0xaf4200d4, 
+0x934205b0, 0xaf4000d4, 0x38420040, 0xa34205b0, 
+0x934205b0, 0x8f4300e8, 0x3042007f, 0xa34205b0, 
+0x24020001, 0x14620005, 0x0, 0x934405b0, 
+0x42102, 0x10000003, 0x348400f0, 0x934405b0, 
+0x3484000f, 0xc004a60, 0x0, 0x2402ff7f, 
+0x282a024, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 
+0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, 
+0x3e00008, 0x27bd0050, 0x3e00008, 0x0, 
+0x27bdffb0, 0x274401b0, 0x26e30028, 0x24650400, 
+0x65102b, 0xafbf0048, 0xafbe0044, 0xafb50040, 
+0xafb3003c, 0xafb20038, 0xafb10034, 0x10400007, 
+0xafb00030, 0x8c820000, 0xac620000, 0x24630004, 
+0x65102b, 0x1440fffb, 0x24840004, 0x8c020080, 
+0xaee20044, 0x8c0200c0, 0xaee20040, 0x8c020084, 
+0xaee20030, 0x8c020084, 0xaee2023c, 0x8c020088, 
+0xaee20240, 0x8c02008c, 0xaee20244, 0x8c020090, 
+0xaee20248, 0x8c020094, 0xaee2024c, 0x8c020098, 
+0xaee20250, 0x8c02009c, 0xaee20254, 0x8c0200a0, 
+0xaee20258, 0x8c0200a4, 0xaee2025c, 0x8c0200a8, 
+0xaee20260, 0x8c0200ac, 0xaee20264, 0x8c0200b0, 
+0xaee20268, 0x8c0200b4, 0xaee2026c, 0x8c0200b8, 
+0xaee20270, 0x8c0200bc, 0x24040001, 0xaee20274, 
+0xaee00034, 0x41080, 0x571021, 0x8ee30034, 
+0x8c42023c, 0x24840001, 0x621821, 0x2c82000f, 
+0xaee30034, 0x1440fff8, 0x41080, 0x8c0200cc, 
+0xaee20048, 0x8c0200d0, 0xaee2004c, 0x8c0200e0, 
+0xaee201f8, 0x8c0200e4, 0xaee201fc, 0x8c0200e8, 
+0xaee20200, 0x8c0200ec, 0xaee20204, 0x8c0200f0, 
+0xaee20208, 0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 
+0x45102b, 0x1040000b, 0x0, 0x8ee200c0, 
+0x8ee300c4, 0x24040001, 0x24050000, 0x651821, 
+0x65302b, 0x441021, 0x461021, 0xaee200c0, 
+0xaee300c4, 0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 
+0x2408ffff, 0x24090000, 0x401821, 0x1021, 
+0x882024, 0xa92824, 0x822025, 0xa32825, 
+0xaee400c0, 0xaee500c4, 0x8ee400d0, 0x8ee500d4, 
+0x8c0200f4, 0x45102b, 0x1040000b, 0x0, 
+0x8ee200d0, 0x8ee300d4, 0x24040001, 0x24050000, 
+0x651821, 0x65302b, 0x441021, 0x461021, 
+0xaee200d0, 0xaee300d4, 0x8c0200f4, 0x8ee400d0, 
+0x8ee500d4, 0x401821, 0x1021, 0x882024, 
+0xa92824, 0x822025, 0xa32825, 0xaee400d0, 
+0xaee500d4, 0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 
+0x45102b, 0x1040000b, 0x0, 0x8ee200c8, 
+0x8ee300cc, 0x24040001, 0x24050000, 0x651821, 
+0x65302b, 0x441021, 0x461021, 0xaee200c8, 
+0xaee300cc, 0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 
+0x401821, 0x1021, 0x882024, 0xa92824, 
+0x822025, 0xa32825, 0x24020008, 0xaee400c8, 
+0xaee500cc, 0xafa20010, 0xafa00014, 0x8f42000c, 
+0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c, 
+0x26e60028, 0x40f809, 0x24070400, 0x104000f0, 
+0x3c020400, 0xafa20020, 0x934205b7, 0x10400089, 
 0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff, 
 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 
 0x609021, 0x1642000e, 0x1e38c0, 0x8f42032c, 
 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 
-0x3c040001, 0x2484322c, 0x3c050009, 0xafa00014, 
-0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, 
+0x3c040001, 0x2484318c, 0x3c050009, 0xafa00014, 
+0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 
 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 
 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 
 0x2021023, 0x2c4203e9, 0x1040001b, 0x9821, 
@@ -5203,241 +5323,129 @@
 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 
 0xaf520018, 0x8f420368, 0x24420001, 0xaf420368, 
 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24843238, 0x3c050009, 
-0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, 
+0x8f820124, 0x3c040001, 0x24843198, 0x3c050009, 
+0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 
 0x8f4202f8, 0x24130001, 0x24420001, 0xaf4202f8, 
-0x8f4202f8, 0x1000001e, 0x326200ff, 0x8f830054, 
+0x8f4202f8, 0x1000001c, 0x326200ff, 0x8f830054, 
 0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, 
-0x10400016, 0x9821, 0x3c150020, 0x24110010, 
-0x8f42000c, 0x8f440150, 0x8f450154, 0x8f860120, 
-0xafb10010, 0xafb20014, 0x551025, 0xafa20018, 
-0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, 
-0x1440ffe3, 0x0, 0x8f820054, 0x2021023, 
-0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, 
-0x14400011, 0x0, 0x8f420368, 0x24420001, 
-0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843240, 
-0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, 
-0xc002a03, 0x3c03821, 0x8f4202dc, 0x24420001, 
-0xaf4202dc, 0x8f4202dc, 0x8f420004, 0x30420001, 
-0x10400033, 0x3c020400, 0x2c21024, 0x10400017, 
-0x0, 0x934205b0, 0x8f440240, 0x8f450244, 
-0x8f4301a4, 0x34420020, 0x14a30006, 0xa34205b0, 
-0x8f420260, 0x8f430264, 0x8f4401a8, 0x10640008, 
-0x0, 0x8f420240, 0x8f430244, 0x934405b0, 
-0x8f460260, 0x8f470264, 0x10000016, 0x38840040, 
-0x934205b0, 0x10000048, 0x304200bf, 0x934205b0, 
-0x8f440240, 0x8f450244, 0x8f4301a4, 0x304200bf, 
-0x14a30006, 0xa34205b0, 0x8f420260, 0x8f430264, 
-0x8f4401a8, 0x1064000b, 0x0, 0x8f420240, 
-0x8f430244, 0x934405b0, 0x8f460260, 0x8f470264, 
-0x38840020, 0xaf4301a4, 0xaf4701a8, 0x10000033, 
-0xa34405b0, 0x934205b0, 0x1000002f, 0x34420020, 
-0x934205b0, 0x8f4300d4, 0x34420020, 0xa34205b0, 
-0x24620001, 0x10000023, 0x28630033, 0x8f4200e4, 
-0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a, 
-0x14400006, 0x24030001, 0x8f4200e8, 0x14430002, 
-0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004, 
-0x30420001, 0x1040000d, 0x3c020400, 0x2c21024, 
-0x10400007, 0x0, 0x934205b0, 0x34420040, 
-0xa34205b0, 0x934205b0, 0x1000000f, 0x304200df, 
-0x934205b0, 0x1000000c, 0x34420060, 0x934205b0, 
-0x8f4300d4, 0x34420020, 0xa34205b0, 0x24620001, 
-0x286300fb, 0x14600005, 0xaf4200d4, 0x934205b0, 
-0xaf4000d4, 0x38420040, 0xa34205b0, 0x934205b0, 
-0x8f4300e8, 0x3042007f, 0xa34205b0, 0x24020001, 
-0x14620005, 0x0, 0x934405b0, 0x42102, 
-0x10000003, 0x348400f0, 0x934405b0, 0x3484000f, 
-0xc004b34, 0x0, 0x2402ff7f, 0x282a024, 
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 
-0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, 
-0x274401b0, 0x26e30028, 0x24650400, 0x65102b, 
-0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, 
-0xafb20038, 0xafb10034, 0x10400007, 0xafb00030, 
-0x8c820000, 0xac620000, 0x24630004, 0x65102b, 
-0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044, 
-0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030, 
-0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240, 
-0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248, 
-0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250, 
-0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258, 
-0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260, 
-0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268, 
-0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270, 
-0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034, 
-0x41080, 0x571021, 0x8ee30034, 0x8c42023c, 
-0x24840001, 0x621821, 0x2c82000f, 0xaee30034, 
-0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048, 
-0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8, 
-0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200, 
-0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208, 
-0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b, 
-0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4, 
-0x24040001, 0x24050000, 0x651821, 0x65302b, 
-0x441021, 0x461021, 0xaee200c0, 0xaee300c4, 
-0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff, 
-0x24090000, 0x401821, 0x1021, 0x882024, 
-0xa92824, 0x822025, 0xa32825, 0xaee400c0, 
-0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4, 
-0x45102b, 0x1040000b, 0x0, 0x8ee200d0, 
-0x8ee300d4, 0x24040001, 0x24050000, 0x651821, 
-0x65302b, 0x441021, 0x461021, 0xaee200d0, 
-0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4, 
-0x401821, 0x1021, 0x882024, 0xa92824, 
-0x822025, 0xa32825, 0xaee400d0, 0xaee500d4, 
-0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b, 
-0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc, 
-0x24040001, 0x24050000, 0x651821, 0x65302b, 
-0x441021, 0x461021, 0xaee200c8, 0xaee300cc, 
-0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821, 
-0x1021, 0x882024, 0xa92824, 0x822025, 
-0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc, 
-0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208, 
-0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028, 
-0x40f809, 0x24070400, 0x104000f0, 0x3c020400, 
-0xafa20020, 0x934205b7, 0x10400089, 0x1821, 
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, 
-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 
-0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 
-0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, 
-0x2484322c, 0x3c050009, 0xafa00014, 0xafa20010, 
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, 
-0x263504c0, 0x8f440168, 0x8f45016c, 0x2201821, 
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, 
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, 
-0x24070008, 0xa32821, 0xa3482b, 0x822021, 
-0x100f809, 0x892021, 0x54400006, 0x24130001, 
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, 
-0x0, 0x326200ff, 0x54400017, 0xaf520018, 
+0x10400014, 0x9821, 0x24110010, 0x8f42000c, 
+0x8f440150, 0x8f450154, 0x8f860120, 0xafb10010, 
+0xafb20014, 0xafa20018, 0x8f42010c, 0x24070008, 
+0x40f809, 0x24c6001c, 0x1440ffe5, 0x0, 
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffef, 
+0x0, 0x326200ff, 0x54400012, 0x24020001, 
 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 
 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24843238, 0x3c050009, 0xafa20014, 
-0x8d460000, 0x10000033, 0x34a50600, 0x8f4202f8, 
-0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, 
-0x9821, 0x24110010, 0x8f42000c, 0x8f440150, 
-0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, 
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, 
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, 
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, 
-0x326200ff, 0x54400012, 0x24020001, 0x8f420368, 
-0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 
-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24843240, 0x3c050009, 0xafa20014, 0x8d460000, 
-0x34a50700, 0xc002a03, 0x3c03821, 0x1021, 
-0x1440005b, 0x24020001, 0x10000065, 0x0, 
-0x8f510018, 0x240200ff, 0x12220002, 0x8021, 
-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 
-0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 
-0x8c020228, 0x3c040001, 0x24843214, 0x3c050009, 
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 
-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440168, 
-0x8f45016c, 0x1021, 0x24070004, 0xafa70010, 
-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021, 
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
-0xa3482b, 0x822021, 0x100f809, 0x892021, 
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x2484321c, 0x3c050009, 
-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 
-0x8f440150, 0x8f450154, 0x8f43000c, 0xaf500018, 
-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 
-0x54400011, 0x24020001, 0x8f420330, 0x24420001, 
-0xaf420330, 0x8f420330, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24843224, 0x3c050009, 
-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002a03, 
-0x2203821, 0x1021, 0x1040000d, 0x24020001, 
-0x8f4202d8, 0xa34005b7, 0xaf4001a0, 0x24420001, 
-0xaf4202d8, 0x8f4202d8, 0x8ee20150, 0x24420001, 
-0xaee20150, 0x10000003, 0x8ee20150, 0x24020001, 
-0xa34205b7, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, 
-0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020, 
-0x8f8200b0, 0x30420004, 0x10400068, 0x0, 
-0x8f43011c, 0x8f820104, 0x14620005, 0x0, 
-0x8f430124, 0x8f8200b4, 0x10620006, 0x0, 
-0x8f820104, 0xaf42011c, 0x8f8200b4, 0x1000005b, 
-0xaf420124, 0x8f8200b0, 0x3c030080, 0x431024, 
-0x1040000d, 0x0, 0x8f82011c, 0x34420002, 
-0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024, 
-0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024, 
-0x1000004a, 0xaf82011c, 0x8f43011c, 0x8f820104, 
-0x14620005, 0x0, 0x8f430124, 0x8f8200b4, 
-0x10620010, 0x0, 0x8f820104, 0xaf42011c, 
-0x8f8200b4, 0x8f43011c, 0xaf420124, 0xafa30010, 
-0x8f420124, 0x3c040001, 0x24843264, 0xafa20014, 
-0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, 
-0x34a50900, 0x8f42011c, 0xafa20010, 0x8f420124, 
-0x3c040001, 0x24843270, 0xafa20014, 0x8f86011c, 
-0x8f8700b0, 0x3c050005, 0xc002a03, 0x34a51000, 
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 
-0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, 
-0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, 
-0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c, 
-0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, 
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 
-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42011c, 
-0xafa20010, 0x8f420124, 0x3c040001, 0x2484327c, 
+0x3c040001, 0x248431a0, 0x3c050009, 0xafa20014, 
+0x8d460000, 0x34a50700, 0xc0029bb, 0x3c03821, 
+0x1021, 0x1440005b, 0x24020001, 0x10000065, 
+0x0, 0x8f510018, 0x240200ff, 0x12220002, 
+0x8021, 0x26300001, 0x8c020228, 0x1602000e, 
+0x1130c0, 0x8f42032c, 0x24420001, 0xaf42032c, 
+0x8f42032c, 0x8c020228, 0x3c040001, 0x24843174, 
+0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 
+0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 
+0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 
+0x8f440168, 0x8f45016c, 0x1021, 0x24070004, 
+0xafa70010, 0xafb00014, 0x8f48000c, 0x24c604c0, 
+0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, 
+0xa32821, 0xa3482b, 0x822021, 0x100f809, 
+0x892021, 0x1440000b, 0x24070008, 0x8f820120, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x2484317c, 
+0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 
+0x34a50200, 0x8f440150, 0x8f450154, 0x8f43000c, 
+0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 
+0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 
+0x24c6001c, 0x54400011, 0x24020001, 0x8f420330, 
+0x24420001, 0xaf420330, 0x8f420330, 0x8f820120, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x24843184, 
+0x3c050009, 0xafa20014, 0x8fa60020, 0x34a50300, 
+0xc0029bb, 0x2203821, 0x1021, 0x1040000d, 
+0x24020001, 0x8f4202d8, 0xa34005b7, 0xaf4001a0, 
+0x24420001, 0xaf4202d8, 0x8f4202d8, 0x8ee20150, 
+0x24420001, 0xaee20150, 0x10000003, 0x8ee20150, 
+0x24020001, 0xa34205b7, 0x8fbf0048, 0x8fbe0044, 
+0x8fb50040, 0x8fb3003c, 0x8fb20038, 0x8fb10034, 
+0x8fb00030, 0x3e00008, 0x27bd0050, 0x27bdffd8, 
+0xafbf0020, 0x8f8200b0, 0x30420004, 0x10400068, 
+0x0, 0x8f43011c, 0x8f820104, 0x14620005, 
+0x0, 0x8f430124, 0x8f8200b4, 0x10620006, 
+0x0, 0x8f820104, 0xaf42011c, 0x8f8200b4, 
+0x1000005b, 0xaf420124, 0x8f8200b0, 0x3c030080, 
+0x431024, 0x1040000d, 0x0, 0x8f82011c, 
+0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb, 
+0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd, 
+0x431024, 0x1000004a, 0xaf82011c, 0x8f43011c, 
+0x8f820104, 0x14620005, 0x0, 0x8f430124, 
+0x8f8200b4, 0x10620010, 0x0, 0x8f820104, 
+0xaf42011c, 0x8f8200b4, 0x8f43011c, 0xaf420124, 
+0xafa30010, 0x8f420124, 0x3c040001, 0x248431c4, 
 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, 
-0x34a51100, 0xc002a03, 0x0, 0x8f8200a0, 
-0x30420004, 0x10400069, 0x0, 0x8f430120, 
-0x8f820124, 0x14620005, 0x0, 0x8f430128, 
-0x8f8200a4, 0x10620006, 0x0, 0x8f820124, 
-0xaf420120, 0x8f8200a4, 0x1000005c, 0xaf420128, 
-0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d, 
-0x0, 0x8f82011c, 0x34420002, 0xaf82011c, 
-0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0, 
-0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b, 
-0xaf82011c, 0x8f430120, 0x8f820124, 0x14620005, 
-0x0, 0x8f430128, 0x8f8200a4, 0x10620010, 
-0x0, 0x8f820124, 0xaf420120, 0x8f8200a4, 
-0x8f430120, 0xaf420128, 0xafa30010, 0x8f420128, 
-0x3c040001, 0x24843288, 0xafa20014, 0x8f86011c, 
-0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, 
+0x10000031, 0x34a50900, 0x8f42011c, 0xafa20010, 
+0x8f420124, 0x3c040001, 0x248431d0, 0xafa20014, 
+0x8f86011c, 0x8f8700b0, 0x3c050005, 0xc0029bb, 
+0x34a51000, 0x8f82011c, 0x34420002, 0xaf82011c, 
+0x8f830104, 0x8f8200b0, 0x34420001, 0xaf8200b0, 
+0x24020008, 0xaf830104, 0xafa20010, 0xafa00014, 
+0x8f42000c, 0x8c040208, 0x8c05020c, 0xafa20018, 
+0x8f42010c, 0x26e60028, 0x40f809, 0x24070400, 
+0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 
+0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 
+0x8f42011c, 0xafa20010, 0x8f420124, 0x3c040001, 
+0x248431dc, 0xafa20014, 0x8f86011c, 0x8f8700b0, 
+0x3c050005, 0x34a51100, 0xc0029bb, 0x0, 
+0x8f8200a0, 0x30420004, 0x10400069, 0x0, 
+0x8f430120, 0x8f820124, 0x14620005, 0x0, 
+0x8f430128, 0x8f8200a4, 0x10620006, 0x0, 
+0x8f820124, 0xaf420120, 0x8f8200a4, 0x1000005c, 
+0xaf420128, 0x8f8200a0, 0x3c030080, 0x431024, 
+0x1040000d, 0x0, 0x8f82011c, 0x34420002, 
+0xaf82011c, 0x8f8200a0, 0x2403fffb, 0x431024, 
+0xaf8200a0, 0x8f82011c, 0x2403fffd, 0x431024, 
+0x1000004b, 0xaf82011c, 0x8f430120, 0x8f820124, 
+0x14620005, 0x0, 0x8f430128, 0x8f8200a4, 
+0x10620010, 0x0, 0x8f820124, 0xaf420120, 
+0x8f8200a4, 0x8f430120, 0xaf420128, 0xafa30010, 
+0x8f420128, 0x3c040001, 0x248431e8, 0xafa20014, 
+0x8f86011c, 0x8f8700a0, 0x3c050005, 0x10000032, 
+0x34a51200, 0x8f420120, 0xafa20010, 0x8f420128, 
+0x3c040001, 0x248431f4, 0xafa20014, 0x8f86011c, 
+0x8f8700a0, 0x3c050005, 0xc0029bb, 0x34a51300, 
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830124, 
+0x8f8200a0, 0x34420001, 0xaf8200a0, 0x24020080, 
+0xaf830124, 0xafa20010, 0xafa00014, 0x8f420014, 
+0x8c040208, 0x8c05020c, 0xafa20018, 0x8f420108, 
+0x3c060001, 0x24c63e84, 0x40f809, 0x24070004, 
+0x8f82011c, 0x2403fffd, 0x431024, 0xaf82011c, 
+0x8ee201dc, 0x24420001, 0xaee201dc, 0x8ee201dc, 
 0x8f420120, 0xafa20010, 0x8f420128, 0x3c040001, 
-0x24843294, 0xafa20014, 0x8f86011c, 0x8f8700a0, 
-0x3c050005, 0xc002a03, 0x34a51300, 0x8f82011c, 
-0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 
-0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, 
-0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, 
-0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, 
-0x24c63f24, 0x40f809, 0x24070004, 0x8f82011c, 
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 
-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420120, 
-0xafa20010, 0x8f420128, 0x3c040001, 0x248432a0, 
-0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, 
-0x34a51400, 0xc002a03, 0x0, 0x8fbf0020, 
-0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, 
-0x3c060080, 0x3c050100, 0x8f820070, 0x481024, 
-0x1040fffd, 0x0, 0x8f820054, 0x24420005, 
-0xaf820078, 0x8c040234, 0x10800016, 0x1821, 
-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, 
-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, 
-0x571021, 0x8c4240e8, 0x44102b, 0x14400009, 
-0x0, 0x3c030080, 0x3c010001, 0x370821, 
-0xac2040e8, 0x3c010001, 0x370821, 0x1000000b, 
-0xa02740f0, 0x3c020001, 0x571021, 0x904240f0, 
-0x54400006, 0x661825, 0x3c020001, 0x571021, 
-0x904240f1, 0x54400001, 0x661825, 0x8c040230, 
-0x10800013, 0x0, 0x3c020001, 0x571021, 
-0x8c4240ec, 0x24420005, 0x3c010001, 0x370821, 
-0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec, 
-0x44102b, 0x14400006, 0x0, 0x3c010001, 
-0x370821, 0xac2040ec, 0x10000006, 0x651825, 
-0x3c020001, 0x571021, 0x904240f2, 0x54400001, 
-0x651825, 0x1060ffbc, 0x0, 0x8f420000, 
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 
-0x1040fffd, 0x0, 0x10000005, 0x0, 
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 
-0x8f820060, 0x431025, 0xaf820060, 0x8f420000, 
-0x10400003, 0x0, 0x1000ffa7, 0xaf80004c, 
-0x1000ffa5, 0xaf800048, 0x3e00008, 0x0, 
+0x24843200, 0xafa20014, 0x8f86011c, 0x8f8700a0, 
+0x3c050005, 0x34a51400, 0xc0029bb, 0x0, 
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3c081000, 
+0x24070001, 0x3c060080, 0x3c050100, 0x8f820070, 
+0x481024, 0x1040fffd, 0x0, 0x8f820054, 
+0x24420005, 0xaf820078, 0x8c040234, 0x10800016, 
+0x1821, 0x3c020001, 0x571021, 0x8c4240e8, 
+0x24420005, 0x3c010001, 0x370821, 0xac2240e8, 
+0x3c020001, 0x571021, 0x8c4240e8, 0x44102b, 
+0x14400009, 0x0, 0x3c030080, 0x3c010001, 
+0x370821, 0xac2040e8, 0x3c010001, 0x370821, 
+0x1000000b, 0xa02740f0, 0x3c020001, 0x571021, 
+0x904240f0, 0x54400006, 0x661825, 0x3c020001, 
+0x571021, 0x904240f1, 0x54400001, 0x661825, 
+0x8c040230, 0x10800013, 0x0, 0x3c020001, 
+0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, 
+0x370821, 0xac2240ec, 0x3c020001, 0x571021, 
+0x8c4240ec, 0x44102b, 0x14400006, 0x0, 
+0x3c010001, 0x370821, 0xac2040ec, 0x10000006, 
+0x651825, 0x3c020001, 0x571021, 0x904240f2, 
+0x54400001, 0x651825, 0x1060ffbc, 0x0, 
+0x8f420000, 0x10400007, 0x0, 0xaf80004c, 
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 
+0x0, 0x8f820060, 0x431025, 0xaf820060, 
+0x8f420000, 0x10400003, 0x0, 0x1000ffa7, 
+0xaf80004c, 0x1000ffa5, 0xaf800048, 0x3e00008, 
 0x0, 0x0, 0x0, 0x27bdffe0, 
 0xafbf001c, 0xafb00018, 0x8f860064, 0x30c20004, 
 0x10400025, 0x24040004, 0x8c020114, 0xaf420020, 
@@ -5480,8 +5488,8 @@
 0x1000006b, 0xaf80004c, 0x10000069, 0xaf800048, 
 0x30c20001, 0x10400004, 0x24020001, 0xaf820064, 
 0x10000063, 0x0, 0x30c20002, 0x1440000b, 
-0x3c050003, 0x3c040001, 0x24843364, 0x34a50500, 
-0x3821, 0xafa00010, 0xc002a03, 0xafa00014, 
+0x3c050003, 0x3c040001, 0x248432c4, 0x34a50500, 
+0x3821, 0xafa00010, 0xc0029bb, 0xafa00014, 
 0x2402ffc0, 0x10000056, 0xaf820064, 0x8c10022c, 
 0x8c02010c, 0x12020047, 0x101080, 0x8c450300, 
 0x26020001, 0x3050003f, 0x24020003, 0xac10022c, 
@@ -5500,7 +5508,7 @@
 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 
 0x0, 0x8f820060, 0x34420100, 0xaf820060, 
 0x8f420000, 0x10400003, 0x0, 0x10000005, 
-0xaf80004c, 0x10000003, 0xaf800048, 0xc002033, 
+0xaf80004c, 0x10000003, 0xaf800048, 0xc00202b, 
 0xa02021, 0x8c02010c, 0x16020002, 0x24020002, 
 0xaf820064, 0x8f820064, 0x30420002, 0x14400004, 
 0x0, 0x8c02010c, 0x1602ffad, 0x0, 
@@ -5509,33 +5517,33 @@
 0x808021, 0x101602, 0x2442ffff, 0x304300ff, 
 0x2c620013, 0xafbf0050, 0xafbe004c, 0xafb50048, 
 0xafb30044, 0xafb20040, 0x104001e6, 0xafb1003c, 
-0x31080, 0x3c010001, 0x220821, 0x8c2233a8, 
+0x31080, 0x3c010001, 0x220821, 0x8c223308, 
 0x400008, 0x0, 0x101302, 0x30440fff, 
 0x24020001, 0x10820005, 0x24020002, 0x1082000a, 
 0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004, 
-0x3c020001, 0x8c423f50, 0xaf4401f0, 0xaf4401f4, 
+0x3c020001, 0x8c423eb0, 0xaf4401f0, 0xaf4401f4, 
 0x10000007, 0x34630001, 0x8f430004, 0xaf4401f0, 
-0xaf4401f4, 0x621824, 0x3c020001, 0x2442c344, 
+0xaf4401f4, 0x621824, 0x3c020001, 0x2442c1b0, 
 0x21100, 0x21182, 0xaf430004, 0x3c030800, 
 0x431025, 0x3c010000, 0xac224138, 0x8f840054, 
 0x41442, 0x41c82, 0x431021, 0x41cc2, 
 0x431023, 0x41d02, 0x431021, 0x41d42, 
 0x431023, 0x10000009, 0xaf4201f8, 0x3c040001, 
-0x24843370, 0x34a51000, 0x2003021, 0x3821, 
-0xafa00010, 0xc002a03, 0xafa00014, 0x8f420290, 
+0x248432d0, 0x34a51000, 0x2003021, 0x3821, 
+0xafa00010, 0xc0029bb, 0xafa00014, 0x8f420290, 
 0x24420001, 0xaf420290, 0x10000215, 0x8f420290, 
-0x27b00028, 0x2002021, 0x24050210, 0xc002a87, 
-0x24060008, 0xc0023a0, 0x2002021, 0x1000020c, 
+0x27b00028, 0x2002021, 0x24050210, 0xc002a3f, 
+0x24060008, 0xc002398, 0x2002021, 0x1000020c, 
 0x0, 0x8c06022c, 0x27a40028, 0x61880, 
 0x24c20001, 0x3046003f, 0x8c650300, 0x61080, 
 0x8c430300, 0x24c20001, 0x3042003f, 0xac02022c, 
-0xafa50028, 0xc0023a0, 0xafa3002c, 0x100001fc, 
+0xafa50028, 0xc002398, 0xafa3002c, 0x100001fc, 
 0x0, 0x27b00028, 0x2002021, 0x24050210, 
-0xc002a87, 0x24060008, 0xc0024df, 0x2002021, 
+0xc002a3f, 0x24060008, 0xc0024d7, 0x2002021, 
 0x100001f3, 0x0, 0x8c06022c, 0x27a40028, 
 0x61880, 0x24c20001, 0x3046003f, 0x8c650300, 
 0x61080, 0x8c430300, 0x24c20001, 0x3042003f, 
-0xac02022c, 0xafa50028, 0xc0024df, 0xafa3002c, 
+0xac02022c, 0xafa50028, 0xc0024d7, 0xafa3002c, 
 0x100001e3, 0x0, 0x101302, 0x30430fff, 
 0x24020001, 0x10620005, 0x24020002, 0x1062001e, 
 0x3c020002, 0x10000033, 0x3c050003, 0x3c030002, 
@@ -5551,8 +5559,8 @@
 0xaf82022c, 0x3c020001, 0x571021, 0x8c4238e0, 
 0xaf820230, 0x3c020001, 0x571021, 0x8c4238e4, 
 0xaf820234, 0x3c02fffd, 0x3442ffff, 0x10000009, 
-0x2c2b024, 0x3c040001, 0x2484337c, 0x34a51100, 
-0x2003021, 0x3821, 0xafa00010, 0xc002a03, 
+0x2c2b024, 0x3c040001, 0x248432dc, 0x34a51100, 
+0x2003021, 0x3821, 0xafa00010, 0xc0029bb, 
 0xafa00014, 0x8f4202bc, 0x24420001, 0xaf4202bc, 
 0x1000019b, 0x8f4202bc, 0x101302, 0x30450fff, 
 0x24020001, 0x10a20005, 0x24020002, 0x10a2000d, 
@@ -5561,25 +5569,25 @@
 0x621824, 0x34630008, 0xaf830220, 0x10000012, 
 0xaf450288, 0x3484fff7, 0x3c03fffb, 0x8f820220, 
 0x3463ffff, 0x2c3b024, 0x441024, 0xaf820220, 
-0x10000009, 0xaf450288, 0x3c040001, 0x24843388, 
+0x10000009, 0xaf450288, 0x3c040001, 0x248432e8, 
 0x34a51200, 0x2003021, 0x3821, 0xafa00010, 
-0xc002a03, 0xafa00014, 0x8f4202ac, 0x24420001, 
+0xc0029bb, 0xafa00014, 0x8f4202ac, 0x24420001, 
 0xaf4202ac, 0x10000172, 0x8f4202ac, 0x27840208, 
-0x24050200, 0xc002a87, 0x24060008, 0x27440214, 
-0x24050200, 0xc002a87, 0x24060008, 0x8f4202b4, 
+0x24050200, 0xc002a3f, 0x24060008, 0x27440214, 
+0x24050200, 0xc002a3f, 0x24060008, 0x8f4202b4, 
 0x24420001, 0xaf4202b4, 0x10000165, 0x8f4202b4, 
 0x101302, 0x30430fff, 0x24020001, 0x10620011, 
 0x28620002, 0x50400005, 0x24020002, 0x10600007, 
 0x0, 0x10000017, 0x0, 0x1062000f, 
 0x0, 0x10000013, 0x0, 0x8c060248, 
-0x2021, 0xc0048a8, 0x24050004, 0x10000007, 
-0x0, 0x8c060248, 0x2021, 0xc0048a8, 
+0x2021, 0xc0047d4, 0x24050004, 0x10000007, 
+0x0, 0x8c060248, 0x2021, 0xc0047d4, 
 0x24050004, 0x10000010, 0x0, 0x8c06024c, 
-0x2021, 0xc0048a8, 0x24050001, 0x1000000a, 
-0x0, 0x3c040001, 0x24843394, 0x3c050003, 
+0x2021, 0xc0047d4, 0x24050001, 0x1000000a, 
+0x0, 0x3c040001, 0x248432f4, 0x3c050003, 
 0x34a51300, 0x2003021, 0x3821, 0xafa00010, 
-0xc002a03, 0xafa00014, 0x8f4202b0, 0x24420001, 
-0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022b4, 
+0xc0029bb, 0xafa00014, 0x8f4202b0, 0x24420001, 
+0xaf4202b0, 0x10000136, 0x8f4202b0, 0xc0022ac, 
 0x0, 0x10000132, 0x0, 0x24020001, 
 0xa34205b6, 0x24100100, 0x8f440198, 0x8f45019c, 
 0xafb00010, 0xafa00014, 0x8f420014, 0xafa20018, 
@@ -5591,7 +5599,7 @@
 0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa0034, 
 0x27c30001, 0x8c020228, 0x609021, 0x1642000e, 
 0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 
-0x8f42032c, 0x8c020228, 0x3c040001, 0x2484332c, 
+0x8f42032c, 0x8c020228, 0x3c040001, 0x2484328c, 
 0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 
 0x1000006b, 0x34a50500, 0xf71021, 0x8fa30020, 
 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 
@@ -5606,7 +5614,7 @@
 0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 
 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 
 0x8faa0034, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24843338, 0x3c050009, 0xafa20014, 0x8d460000, 
+0x24843298, 0x3c050009, 0xafa20014, 0x8d460000, 
 0x10000033, 0x34a50600, 0x8f4202f8, 0x24130001, 
 0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001c, 
 0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, 
@@ -5618,26 +5626,26 @@
 0x2c4203e9, 0x1440ffef, 0x0, 0x326200ff, 
 0x14400011, 0x0, 0x8f420368, 0x24420001, 
 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa0034, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843340, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x248432a0, 
 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, 
-0xc002a03, 0x3c03821, 0x8f4202a0, 0x24420001, 
+0xc0029bb, 0x3c03821, 0x8f4202a0, 0x24420001, 
 0xaf4202a0, 0x8f4202a0, 0x8f4202e8, 0x24420001, 
 0xaf4202e8, 0x1000008a, 0x8f4202e8, 0x8c02025c, 
 0x27440214, 0xaf4201e0, 0x8c020260, 0x24050200, 
-0x24060008, 0xc002a87, 0xaf4201e8, 0x8f820220, 
+0x24060008, 0xc002a3f, 0xaf4201e8, 0x8f820220, 
 0x30420008, 0x14400002, 0x24020001, 0x24020002, 
 0xaf420288, 0x8f42029c, 0x24420001, 0xaf42029c, 
 0x10000077, 0x8f42029c, 0x3c0200ff, 0x3442ffff, 
 0x2021824, 0x32c20180, 0x14400006, 0x3402fffb, 
 0x43102b, 0x14400003, 0x0, 0x1000006c, 
-0xaf4300bc, 0x3c040001, 0x248433a0, 0x3c050003, 
+0xaf4300bc, 0x3c040001, 0x24843300, 0x3c050003, 
 0x34a51500, 0x2003021, 0x3821, 0xafa00010, 
-0xc002a03, 0xafa00014, 0x3c020700, 0x34421000, 
+0xc0029bb, 0xafa00014, 0x3c020700, 0x34421000, 
 0x101e02, 0x621825, 0xafa30020, 0x8f510018, 
 0x240200ff, 0x12220002, 0x8021, 0x26300001, 
 0x8c020228, 0x1602000e, 0x1130c0, 0x8f42032c, 
 0x24420001, 0xaf42032c, 0x8f42032c, 0x8c020228, 
-0x3c040001, 0x24843314, 0x3c050009, 0xafa00014, 
+0x3c040001, 0x24843274, 0x3c050009, 0xafa00014, 
 0xafa20010, 0x8fa60020, 0x1000003f, 0x34a50100, 
 0xd71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 
 0xac4404c4, 0xc01821, 0x8f440168, 0x8f45016c, 
@@ -5646,15 +5654,15 @@
 0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, 
 0x822021, 0x100f809, 0x892021, 0x1440000b, 
 0x24070008, 0x8f820120, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x2484331c, 0x3c050009, 0xafa20014, 
+0x3c040001, 0x2484327c, 0x3c050009, 0xafa20014, 
 0x8fa60020, 0x1000001c, 0x34a50200, 0x8f440150, 
 0x8f450154, 0x8f43000c, 0xaf500018, 0x8f860120, 
 0x24020010, 0xafa20010, 0xafb00014, 0xafa30018, 
 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400010, 
 0x0, 0x8f420330, 0x24420001, 0xaf420330, 
 0x8f420330, 0x8f820120, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24843324, 0x3c050009, 0xafa20014, 
-0x8fa60020, 0x34a50300, 0xc002a03, 0x2203821, 
+0x3c040001, 0x24843284, 0x3c050009, 0xafa20014, 
+0x8fa60020, 0x34a50300, 0xc0029bb, 0x2203821, 
 0x8f4202d0, 0x24420001, 0xaf4202d0, 0x8f4202d0, 
 0x8f4202e0, 0x24420001, 0xaf4202e0, 0x8f4202e0, 
 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 
@@ -5674,21 +5682,21 @@
 0x431024, 0x34420004, 0xaf820200, 0x8f53034c, 
 0x8f550350, 0x8f5e0354, 0x8f470358, 0xafa70014, 
 0x8f4202c0, 0x274401b0, 0x24420001, 0xaf4202c0, 
-0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a70, 
+0x8f5002c0, 0x8f5101f4, 0x8f5201f0, 0xc002a28, 
 0x24050400, 0xaf53034c, 0xaf550350, 0xaf5e0354, 
 0x8fa70014, 0xaf470358, 0xaf5002c0, 0xaf5101f4, 
 0xaf5201f0, 0x8c02025c, 0x27440214, 0xaf4201e0, 
 0x8c020260, 0x24050200, 0x24060008, 0xaf4201e8, 
-0x24020006, 0xc002a87, 0xaf4201e4, 0x3c023b9a, 
+0x24020006, 0xc002a3f, 0xaf4201e4, 0x3c023b9a, 
 0x3442ca00, 0xaf4201ec, 0x240203e8, 0x24040002, 
 0x24030001, 0xaf420284, 0xaf440280, 0xaf43028c, 
 0x8f820220, 0x30420008, 0x10400004, 0x0, 
 0xaf430288, 0x10000003, 0x3021, 0xaf440288, 
-0x3021, 0x3c030001, 0x661821, 0x90633d90, 
+0x3021, 0x3c030001, 0x661821, 0x90633cf0, 
 0x3461021, 0x24c60001, 0xa043021c, 0x2cc2000f, 
 0x1440fff8, 0x3461821, 0x24c60001, 0x8f820040, 
 0x24040080, 0x24050080, 0x21702, 0x24420030, 
-0xa062021c, 0x3461021, 0xc002a70, 0xa040021c, 
+0xa062021c, 0x3461021, 0xc002a28, 0xa040021c, 
 0x8fa7001c, 0x30e20004, 0x14400006, 0x0, 
 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 
 0xaf820220, 0x8fa70024, 0x30e20004, 0x14400006, 
@@ -5712,7 +5720,7 @@
 0x2c450001, 0xa01021, 0x14400009, 0x24840008, 
 0x86102b, 0x1440fff0, 0x1021, 0x304200ff, 
 0x14400030, 0x24020001, 0x1000002e, 0x1021, 
-0x1000fffa, 0x24020001, 0x2002021, 0xc00229a, 
+0x1000fffa, 0x24020001, 0x2002021, 0xc002292, 
 0x24050006, 0x3042007f, 0x218c0, 0x2e31021, 
 0x3c010001, 0x220821, 0x942230d0, 0x1040fff2, 
 0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0, 
@@ -5727,7 +5735,7 @@
 0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0, 
 0x801021, 0xafb00030, 0x24500002, 0x2002021, 
 0x24050006, 0xafb10034, 0x408821, 0xafbf0048, 
-0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00229a, 
+0xafbe0044, 0xafb50040, 0xafb3003c, 0xc002292, 
 0xafb20038, 0x3047007f, 0x710c0, 0x2e21021, 
 0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c, 
 0xa03021, 0x3c090001, 0x352934d2, 0x96280002, 
@@ -5740,15 +5748,15 @@
 0x10c00014, 0x610c0, 0x571821, 0x3c010001, 
 0x230821, 0x8c2334d0, 0x571021, 0xafa30010, 
 0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, 
-0x248434b4, 0xafa20014, 0x8e260000, 0x8e270004, 
-0x3c050004, 0xc002a03, 0x34a50400, 0x10000063, 
+0x24843414, 0xafa20014, 0x8e260000, 0x8e270004, 
+0x3c050004, 0xc0029bb, 0x34a50400, 0x10000063, 
 0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, 
 0x2e21021, 0x3c010001, 0x220821, 0x942234d0, 
 0xaf420100, 0xa03021, 0x14c00011, 0x628c0, 
 0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, 
-0x220821, 0x942230d0, 0x3c040001, 0x248434c0, 
+0x220821, 0x942230d0, 0x3c040001, 0x24843420, 
 0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, 
-0xc002a03, 0x34a50500, 0x10000048, 0x3c020800, 
+0xc0029bb, 0x34a50500, 0x10000048, 0x3c020800, 
 0xb71821, 0x3c020001, 0x96040000, 0x344234d2, 
 0x621821, 0xa4640000, 0x8e020002, 0x720c0, 
 0xac620002, 0x2e41021, 0x3c030001, 0x621821, 
@@ -5771,7 +5779,7 @@
 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 
 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 
 0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 
-0x8c020228, 0x3c040001, 0x2484347c, 0x3c050009, 
+0x8c020228, 0x3c040001, 0x248433dc, 0x3c050009, 
 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 
 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 
 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 
@@ -5785,7 +5793,7 @@
 0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 
 0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 
 0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24843488, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x248433e8, 
 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 
 0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 
 0xaf4202f8, 0x8f4202f8, 0x1000001c, 0x326200ff, 
@@ -5798,8 +5806,8 @@
 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 
 0x0, 0x8f420368, 0x24420001, 0xaf420368, 
 0x8f420368, 0x8f820120, 0x8faa002c, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24843490, 0x3c050009, 
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002a03, 
+0x8f820124, 0x3c040001, 0x248433f0, 0x3c050009, 
+0xafa20014, 0x8d460000, 0x34a50700, 0xc0029bb, 
 0x3c03821, 0x8f4202a4, 0x24420001, 0xaf4202a4, 
 0x8f4202a4, 0x8f4202e4, 0x24420001, 0xaf4202e4, 
 0x8f4202e4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 
@@ -5807,7 +5815,7 @@
 0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021, 
 0xafb00040, 0x24500002, 0x2002021, 0x24050006, 
 0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054, 
-0xafb50050, 0xafb3004c, 0xc00229a, 0xafb20048, 
+0xafb50050, 0xafb3004c, 0xc002292, 0xafb20048, 
 0x3048007f, 0x810c0, 0x2e21021, 0x3c060001, 
 0xc23021, 0x94c630d0, 0x10c0001c, 0x3821, 
 0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0, 
@@ -5819,8 +5827,8 @@
 0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, 
 0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, 
 0x3c010001, 0x220821, 0x942230d0, 0x3c040001, 
-0x248434cc, 0xafa20014, 0x8e260000, 0x8e270004, 
-0x3c050004, 0xc002a03, 0x34a50900, 0x10000075, 
+0x2484342c, 0xafa20014, 0x8e260000, 0x8e270004, 
+0x3c050004, 0xc0029bb, 0x34a50900, 0x10000075, 
 0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, 
 0x3c030001, 0x621821, 0x946334d0, 0x710c0, 
 0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, 
@@ -5855,7 +5863,7 @@
 0xafab0034, 0x27c30001, 0x8c020228, 0x609021, 
 0x1642000e, 0x1e38c0, 0x8f42032c, 0x24420001, 
 0xaf42032c, 0x8f42032c, 0x8c020228, 0x3c040001, 
-0x2484347c, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x248433dc, 0x3c050009, 0xafa00014, 0xafa20010, 
 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 
 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
@@ -5869,7 +5877,7 @@
 0x0, 0x326200ff, 0x54400017, 0xaf520018, 
 0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 
 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24843488, 0x3c050009, 0xafa20014, 
+0x3c040001, 0x248433e8, 0x3c050009, 0xafa20014, 
 0x8d660000, 0x10000033, 0x34a50600, 0x8f4202f8, 
 0x24130001, 0x24420001, 0xaf4202f8, 0x8f4202f8, 
 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 
@@ -5882,14 +5890,14 @@
 0x326200ff, 0x14400011, 0x0, 0x8f420368, 
 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 
 0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24843490, 0x3c050009, 0xafa20014, 0x8d660000, 
-0x34a50700, 0xc002a03, 0x3c03821, 0x8f4202a8, 
+0x248433f0, 0x3c050009, 0xafa20014, 0x8d660000, 
+0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202a8, 
 0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f4202e4, 
 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x8fbf0058, 
 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 
 0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 
 0x0, 0x0, 0x0, 0x27bdffe0, 
-0x27644000, 0xafbf0018, 0xc002a70, 0x24051000, 
+0x27644000, 0xafbf0018, 0xc002a28, 0x24051000, 
 0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, 
 0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, 
 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, 
@@ -5898,15 +5906,15 @@
 0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, 
 0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, 
 0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, 
-0x3c040001, 0x24843590, 0x3c050001, 0x34420001, 
+0x3c040001, 0x248434f0, 0x3c050001, 0x34420001, 
 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, 
-0x34a50100, 0xc002a03, 0x3821, 0x8c020218, 
+0x34a50100, 0xc0029bb, 0x3821, 0x8c020218, 
 0x30420040, 0x10400014, 0x0, 0x8f82011c, 
-0x3c040001, 0x2484359c, 0x3c050001, 0x34420004, 
+0x3c040001, 0x248434fc, 0x3c050001, 0x34420004, 
 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, 
-0x10000007, 0x34a50200, 0x3c040001, 0x248435a4, 
+0x10000007, 0x34a50200, 0x3c040001, 0x24843504, 
 0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, 
-0xc002a03, 0x3821, 0x8fbf0018, 0x3e00008, 
+0xc0029bb, 0x3821, 0x8fbf0018, 0x3e00008, 
 0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, 
 0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, 
 0x24680020, 0x27684800, 0x8f820128, 0x11020004, 
@@ -5927,237 +5935,221 @@
 0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021, 
 0x402021, 0x24020001, 0xaf4400f4, 0xac890000, 
 0xac820004, 0x24020001, 0x3e00008, 0x0, 
-0x3e00008, 0x0, 0x8fa90010, 0x8faa0014, 
-0x8f830120, 0x8fab0018, 0x27624fe0, 0x14620002, 
-0x24680020, 0x27684800, 0x8f820128, 0x1102000f, 
-0x24620016, 0xac640000, 0xac650004, 0xac660008, 
-0xa467000e, 0xac690018, 0xac6a001c, 0xac620014, 
-0xac6b0010, 0xaf880120, 0x8f4300fc, 0x24020001, 
-0x2463ffff, 0x10000006, 0xaf4300fc, 0x8f430324, 
-0x1021, 0x24630001, 0xaf430324, 0x8f430324, 
-0x3e00008, 0x0, 0x3e00008, 0x0, 
-0x8fa90010, 0x8f83010c, 0x8faa0014, 0x8fab0018, 
-0x1060000a, 0x276247e0, 0x14620002, 0x24680020, 
-0x27684000, 0x8f820108, 0x11020004, 0x0, 
-0x8f820104, 0x15020007, 0x0, 0x8f430328, 
-0x1021, 0x24630001, 0xaf430328, 0x10000035, 
-0x8f430328, 0xac640000, 0xac650004, 0xac660008, 
-0xa467000e, 0xac690018, 0xac6a001c, 0xac6b0010, 
-0xac620014, 0xaf880100, 0x8f4400ec, 0x8c820000, 
-0x30420006, 0x10400019, 0x31220006, 0x10400018, 
-0x3c020001, 0x8c830004, 0x2c620010, 0x10400013, 
-0x3c020001, 0x24630001, 0xac830004, 0x8f4300f0, 
-0x34422ec0, 0x2e21021, 0x54620004, 0x24620008, 
-0x3c020001, 0x34422cc0, 0x2e21021, 0x14440015, 
-0x24020001, 0x8f820108, 0x24420020, 0xaf820108, 
-0x8f820108, 0x1000000f, 0x24020001, 0x3c020001, 
-0x34422ec0, 0x2e21021, 0x54820004, 0x24820008, 
-0x3c020001, 0x34422cc0, 0x2e21021, 0x402021, 
-0x24020001, 0xaf4400ec, 0xac890000, 0xac820004, 
-0x24020001, 0x3e00008, 0x0, 0x3e00008, 
-0x0, 0x8fa30010, 0x8faa0014, 0x8f880100, 
-0x8fab0018, 0x276247e0, 0x15020002, 0x25090020, 
-0x27694000, 0x8f820108, 0x1122000d, 0x0, 
-0xad030018, 0x25030016, 0xad040000, 0xad050004, 
-0xad060008, 0xa507000e, 0xad0a001c, 0xad030014, 
-0xad0b0010, 0xaf890100, 0x10000006, 0x24020001, 
-0x8f430328, 0x1021, 0x24630001, 0xaf430328, 
-0x8f430328, 0x3e00008, 0x0, 0x3e00008, 
-0x0, 0x27bdffd8, 0x3c040001, 0x248435ac, 
-0x3c050001, 0xafbf0024, 0xafb20020, 0xafb1001c, 
-0xafb00018, 0x8f900104, 0x8f9100b0, 0x8f92011c, 
-0x34a52500, 0x8f820100, 0x2403021, 0x2203821, 
-0xafa20010, 0xc002a03, 0xafb00014, 0x8e020008, 
-0xafa20010, 0x8e02000c, 0x3c040001, 0x248435b8, 
-0xafa20014, 0x8e060000, 0x8e070004, 0x3c050001, 
-0xc002a03, 0x34a52510, 0x8e020018, 0xafa20010, 
-0x8e02001c, 0x3c040001, 0x248435c4, 0xafa20014, 
-0x8e060010, 0x8e070014, 0x3c050001, 0xc002a03, 
-0x34a52520, 0x3c027f00, 0x2221024, 0x3c030800, 
-0x54430016, 0x3c030200, 0x8f82009c, 0x3042ffff, 
-0x14400012, 0x3c030200, 0x3c040001, 0x248435d0, 
-0x3c050002, 0x34a5f030, 0x3021, 0x3821, 
-0x36420002, 0xaf82011c, 0x36220001, 0xaf8200b0, 
-0xaf900104, 0xaf92011c, 0xafa00010, 0xc002a03, 
-0xafa00014, 0x10000024, 0x0, 0x2c31024, 
-0x1040000d, 0x2231024, 0x1040000b, 0x36420002, 
-0xaf82011c, 0x36220001, 0xaf8200b0, 0xaf900104, 
-0xaf92011c, 0x8f420320, 0x24420001, 0xaf420320, 
-0x10000015, 0x8f420320, 0x3c040001, 0x248435d8, 
-0x240202a2, 0xafa20010, 0xafa00014, 0x8f860144, 
-0x3c070001, 0x24e735e0, 0xc002a03, 0x3405dead, 
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f820220, 
-0x34420004, 0xaf820220, 0x8f820140, 0x3c030001, 
-0x431025, 0xaf820140, 0x8fbf0024, 0x8fb20020, 
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 
-0x27bdffd8, 0x3c040001, 0x24843608, 0x3c050001, 
-0xafbf0024, 0xafb20020, 0xafb1001c, 0xafb00018, 
-0x8f900124, 0x8f9100a0, 0x8f92011c, 0x34a52600, 
-0x8f820120, 0x2403021, 0x2203821, 0xafa20010, 
-0xc002a03, 0xafb00014, 0x8e020008, 0xafa20010, 
-0x8e02000c, 0x3c040001, 0x24843614, 0xafa20014, 
-0x8e060000, 0x8e070004, 0x3c050001, 0xc002a03, 
-0x34a52610, 0x8e020018, 0xafa20010, 0x8e02001c, 
-0x3c040001, 0x24843620, 0xafa20014, 0x8e060010, 
-0x8e070014, 0x3c050001, 0xc002a03, 0x34a52620, 
-0x3c027f00, 0x2221024, 0x3c030800, 0x54430016, 
-0x3c030200, 0x8f8200ac, 0x3042ffff, 0x14400012, 
-0x3c030200, 0x3c040001, 0x2484362c, 0x3c050001, 
-0x34a5f030, 0x3021, 0x3821, 0x36420002, 
-0xaf82011c, 0x36220001, 0xaf8200a0, 0xaf900124, 
-0xaf92011c, 0xafa00010, 0xc002a03, 0xafa00014, 
-0x10000024, 0x0, 0x2c31024, 0x1040000d, 
-0x2231024, 0x1040000b, 0x36420002, 0xaf82011c, 
-0x36220001, 0xaf8200a0, 0xaf900124, 0xaf92011c, 
-0x8f42031c, 0x24420001, 0xaf42031c, 0x10000015, 
-0x8f42031c, 0x3c040001, 0x248435d8, 0x240202db, 
-0xafa20010, 0xafa00014, 0x8f860144, 0x3c070001, 
-0x24e735e0, 0xc002a03, 0x3405dead, 0x8f82011c, 
-0x34420002, 0xaf82011c, 0x8f820220, 0x34420004, 
-0xaf820220, 0x8f820140, 0x3c030001, 0x431025, 
-0xaf820140, 0x8fbf0024, 0x8fb20020, 0x8fb1001c, 
-0x8fb00018, 0x3e00008, 0x27bd0028, 0x6021, 
-0x5021, 0x3021, 0x2821, 0x6821, 
-0x4821, 0x7821, 0x7021, 0x8f880124, 
-0x8f870104, 0x1580002e, 0x8f8b011c, 0x11a00014, 
-0x31620800, 0x8f820120, 0x10460029, 0x0, 
-0x3c040001, 0x8c843f30, 0x8cc20000, 0x8cc30004, 
+0x3e00008, 0x0, 0x8fa90010, 0x8f83010c, 
+0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0, 
+0x14620002, 0x24680020, 0x27684000, 0x8f820108, 
+0x11020004, 0x0, 0x8f820104, 0x15020007, 
+0x0, 0x8f430328, 0x1021, 0x24630001, 
+0xaf430328, 0x10000035, 0x8f430328, 0xac640000, 
+0xac650004, 0xac660008, 0xa467000e, 0xac690018, 
+0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100, 
+0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019, 
+0x31220006, 0x10400018, 0x3c020001, 0x8c830004, 
+0x2c620010, 0x10400013, 0x3c020001, 0x24630001, 
+0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021, 
+0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, 
+0x2e21021, 0x14440015, 0x24020001, 0x8f820108, 
+0x24420020, 0xaf820108, 0x8f820108, 0x1000000f, 
+0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021, 
+0x54820004, 0x24820008, 0x3c020001, 0x34422cc0, 
+0x2e21021, 0x402021, 0x24020001, 0xaf4400ec, 
+0xac890000, 0xac820004, 0x24020001, 0x3e00008, 
+0x0, 0x3e00008, 0x0, 0x27bdffd8, 
+0x3c040001, 0x2484350c, 0x3c050001, 0xafbf0024, 
+0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104, 
+0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100, 
+0x2403021, 0x2203821, 0xafa20010, 0xc0029bb, 
+0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, 
+0x3c040001, 0x24843518, 0xafa20014, 0x8e060000, 
+0x8e070004, 0x3c050001, 0xc0029bb, 0x34a52510, 
+0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, 
+0x24843524, 0xafa20014, 0x8e060010, 0x8e070014, 
+0x3c050001, 0xc0029bb, 0x34a52520, 0x3c027f00, 
+0x2221024, 0x3c030800, 0x54430016, 0x3c030200, 
+0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200, 
+0x3c040001, 0x24843530, 0x3c050002, 0x34a5f030, 
+0x3021, 0x3821, 0x36420002, 0xaf82011c, 
+0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, 
+0xafa00010, 0xc0029bb, 0xafa00014, 0x10000024, 
+0x0, 0x2c31024, 0x1040000d, 0x2231024, 
+0x1040000b, 0x36420002, 0xaf82011c, 0x36220001, 
+0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420320, 
+0x24420001, 0xaf420320, 0x10000015, 0x8f420320, 
+0x3c040001, 0x24843538, 0x240202a9, 0xafa20010, 
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e73540, 
+0xc0029bb, 0x3405dead, 0x8f82011c, 0x34420002, 
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, 
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140, 
+0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 
+0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001, 
+0x24843568, 0x3c050001, 0xafbf0024, 0xafb20020, 
+0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0, 
+0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021, 
+0x2203821, 0xafa20010, 0xc0029bb, 0xafb00014, 
+0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001, 
+0x24843574, 0xafa20014, 0x8e060000, 0x8e070004, 
+0x3c050001, 0xc0029bb, 0x34a52610, 0x8e020018, 
+0xafa20010, 0x8e02001c, 0x3c040001, 0x24843580, 
+0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001, 
+0xc0029bb, 0x34a52620, 0x3c027f00, 0x2221024, 
+0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac, 
+0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001, 
+0x2484358c, 0x3c050001, 0x34a5f030, 0x3021, 
+0x3821, 0x36420002, 0xaf82011c, 0x36220001, 
+0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010, 
+0xc0029bb, 0xafa00014, 0x10000024, 0x0, 
+0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, 
+0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, 
+0xaf900124, 0xaf92011c, 0x8f42031c, 0x24420001, 
+0xaf42031c, 0x10000015, 0x8f42031c, 0x3c040001, 
+0x24843538, 0x240202e2, 0xafa20010, 0xafa00014, 
+0x8f860144, 0x3c070001, 0x24e73540, 0xc0029bb, 
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, 
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 
+0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, 
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 
+0x27bd0028, 0x6021, 0x5021, 0x3021, 
+0x2821, 0x6821, 0x4821, 0x7821, 
+0x7021, 0x8f880124, 0x8f870104, 0x1580002e, 
+0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, 
+0x10460029, 0x0, 0x3c040001, 0x8c843e90, 
+0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, 
+0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 
+0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, 
+0x10000012, 0x24c60020, 0x10400017, 0x0, 
+0x3c040001, 0x8c843e90, 0x8d020000, 0x8d030004, 
+0xac820000, 0xac830004, 0x8d020008, 0xac820008, 
+0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, 
+0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 
+0xac820014, 0x27624fe0, 0x43102b, 0x54400001, 
+0x27634800, 0x603021, 0x1540002f, 0x31620100, 
+0x11200014, 0x31628000, 0x8f820100, 0x1045002a, 
+0x31620100, 0x3c040001, 0x8c843e8c, 0x8ca20000, 
+0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, 
+0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, 
+0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, 
+0x24a50020, 0x10400018, 0x31620100, 0x3c040001, 
+0x8c843e8c, 0x8ce20000, 0x8ce30004, 0xac820000, 
+0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, 
+0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, 
+0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, 
+0x276247e0, 0x43102b, 0x54400001, 0x27634000, 
+0x602821, 0x31620100, 0x5440001d, 0x31621000, 
+0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 
+0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, 
+0x8f880124, 0x6821, 0x11800011, 0x31621000, 
+0x3c040001, 0x8c843e90, 0x8c820000, 0x8c830004, 
+0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, 
+0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, 
+0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, 
+0x1440ff82, 0x0, 0x1120000f, 0x31220800, 
+0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, 
+0x3c020002, 0x1221024, 0x10400004, 0x24e20020, 
+0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, 
+0x8f870104, 0x4821, 0x1140ff70, 0x0, 
+0x3c040001, 0x8c843e8c, 0x8c820000, 0x8c830004, 
+0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, 
+0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, 
+0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, 
+0x3e00008, 0x0, 0x6021, 0x5821, 
+0x3021, 0x2821, 0x6821, 0x5021, 
+0x7821, 0x7021, 0x8f880124, 0x8f870104, 
+0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, 
+0x31220800, 0x8f820120, 0x10460029, 0x0, 
+0x3c040001, 0x8c843e90, 0x8cc20000, 0x8cc30004, 
 0xac820000, 0xac830004, 0x8cc20008, 0xac820008, 
 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, 
 0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, 
-0x10400017, 0x0, 0x3c040001, 0x8c843f30, 
+0x10400017, 0x0, 0x3c040001, 0x8c843e90, 
 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, 
 0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 
 0x8d020010, 0x25060020, 0xac820010, 0x8d020014, 
 0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, 
 0x43102b, 0x54400001, 0x27634800, 0x603021, 
-0x1540002f, 0x31620100, 0x11200014, 0x31628000, 
-0x8f820100, 0x1045002a, 0x31620100, 0x3c040001, 
-0x8c843f2c, 0x8ca20000, 0x8ca30004, 0xac820000, 
+0x1560002f, 0x31220100, 0x11400014, 0x31228000, 
+0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, 
+0x8c843e8c, 0x8ca20000, 0x8ca30004, 0xac820000, 
 0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, 
-0xa482000e, 0x8ca20010, 0x240a0001, 0xac820010, 
+0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, 
 0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, 
-0x31620100, 0x3c040001, 0x8c843f2c, 0x8ce20000, 
+0x31220100, 0x3c040001, 0x8c843e8c, 0x8ce20000, 
 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, 
 0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, 
-0x24e50020, 0xac820010, 0x8ce20014, 0x240a0001, 
+0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, 
 0xa01821, 0xac820014, 0x276247e0, 0x43102b, 
-0x54400001, 0x27634000, 0x602821, 0x31620100, 
-0x5440001d, 0x31621000, 0x11a00009, 0x31a20800, 
+0x54400001, 0x27634000, 0x602821, 0x31220100, 
+0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, 
 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, 
 0x25020020, 0xaf820124, 0x8f880124, 0x6821, 
-0x11800011, 0x31621000, 0x3c040001, 0x8c843f30, 
+0x11800011, 0x31221000, 0x3c040001, 0x8c843e90, 
 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, 
 0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 
 0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, 
-0x8c8f0014, 0x31621000, 0x1440ff82, 0x0, 
-0x1120000f, 0x31220800, 0x10400004, 0x3c020002, 
-0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1221024, 
+0x8c8f0014, 0x31221000, 0x14400022, 0x0, 
+0x1140000f, 0x31420800, 0x10400004, 0x3c020002, 
+0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, 
 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, 
-0x24e20020, 0xaf820104, 0x8f870104, 0x4821, 
-0x1140ff70, 0x0, 0x3c040001, 0x8c843f2c, 
+0x24e20020, 0xaf820104, 0x8f870104, 0x5021, 
+0x11600010, 0x0, 0x3c040001, 0x8c843e8c, 
 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, 
 0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, 
-0x8c820010, 0x5021, 0xaf8200b0, 0x8c890010, 
-0x1000ff60, 0x8c8e0014, 0x3e00008, 0x0, 
-0x6021, 0x5821, 0x3021, 0x2821, 
-0x6821, 0x5021, 0x7821, 0x7021, 
-0x8f880124, 0x8f870104, 0x3c180100, 0x1580002e, 
-0x8f89011c, 0x11a00014, 0x31220800, 0x8f820120, 
-0x10460029, 0x0, 0x3c040001, 0x8c843f30, 
-0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, 
-0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 
-0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, 
-0x10000012, 0x24c60020, 0x10400017, 0x0, 
-0x3c040001, 0x8c843f30, 0x8d020000, 0x8d030004, 
-0xac820000, 0xac830004, 0x8d020008, 0xac820008, 
-0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, 
-0xac820010, 0x8d020014, 0x240c0001, 0xc01821, 
-0xac820014, 0x27624fe0, 0x43102b, 0x54400001, 
-0x27634800, 0x603021, 0x1560002f, 0x31220100, 
-0x11400014, 0x31228000, 0x8f820100, 0x1045002a, 
-0x31220100, 0x3c040001, 0x8c843f2c, 0x8ca20000, 
-0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, 
-0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, 
-0x240b0001, 0xac820010, 0x8ca20014, 0x10000012, 
-0x24a50020, 0x10400018, 0x31220100, 0x3c040001, 
-0x8c843f2c, 0x8ce20000, 0x8ce30004, 0xac820000, 
-0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, 
-0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, 
-0x8ce20014, 0x240b0001, 0xa01821, 0xac820014, 
-0x276247e0, 0x43102b, 0x54400001, 0x27634000, 
-0x602821, 0x31220100, 0x5440001d, 0x31221000, 
-0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 
-0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, 
-0x8f880124, 0x6821, 0x11800011, 0x31221000, 
-0x3c040001, 0x8c843f30, 0x8c820000, 0x8c830004, 
-0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, 
-0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, 
-0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31221000, 
-0x14400022, 0x0, 0x1140000f, 0x31420800, 
-0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, 
-0x3c020002, 0x1421024, 0x10400004, 0x24e20020, 
-0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, 
-0x8f870104, 0x5021, 0x11600010, 0x0, 
-0x3c040001, 0x8c843f2c, 0x8c820000, 0x8c830004, 
-0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, 
-0x9482000e, 0xaf82009c, 0x8c820010, 0x5821, 
-0xaf8200b0, 0x8c8a0010, 0x8c8e0014, 0x8f820070, 
-0x3c031000, 0x431024, 0x1040ff5c, 0x0, 
-0x8f820054, 0x24420005, 0xaf820078, 0x8c040234, 
-0x10800016, 0x1821, 0x3c020001, 0x571021, 
-0x8c4240e8, 0x24420005, 0x3c010001, 0x370821, 
-0xac2240e8, 0x3c020001, 0x571021, 0x8c4240e8, 
-0x44102b, 0x14400009, 0x24020001, 0x3c030080, 
-0x3c010001, 0x370821, 0xac2040e8, 0x3c010001, 
-0x370821, 0x1000000c, 0xa02240f0, 0x3c020001, 
-0x571021, 0x904240f0, 0x14400006, 0x3c020080, 
-0x3c020001, 0x571021, 0x904240f1, 0x10400002, 
-0x3c020080, 0x621825, 0x8c040230, 0x10800013, 
-0x0, 0x3c020001, 0x571021, 0x8c4240ec, 
-0x24420005, 0x3c010001, 0x370821, 0xac2240ec, 
-0x3c020001, 0x571021, 0x8c4240ec, 0x44102b, 
-0x14400006, 0x0, 0x3c010001, 0x370821, 
-0xac2040ec, 0x10000006, 0x781825, 0x3c020001, 
-0x571021, 0x904240f2, 0x54400001, 0x781825, 
-0x1060ff1a, 0x0, 0x8f420000, 0x10400007, 
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, 
-0x0, 0x10000005, 0x0, 0xaf800048, 
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060, 
-0x431025, 0xaf820060, 0x8f420000, 0x10400003, 
-0x0, 0x1000ff05, 0xaf80004c, 0x1000ff03, 
-0xaf800048, 0x3e00008, 0x0, 0x3c020001, 
-0x8c423db8, 0x27bdffe8, 0xafbf0014, 0x14400012, 
-0xafb00010, 0x3c100001, 0x26103fd0, 0x2002021, 
-0xc002a70, 0x24052000, 0x26021fe0, 0x3c010001, 
-0xac223f38, 0x3c010001, 0xac223f34, 0xac020250, 
+0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, 
+0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, 
+0x1040ff5c, 0x0, 0x8f820054, 0x24420005, 
+0xaf820078, 0x8c040234, 0x10800016, 0x1821, 
+0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, 
+0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, 
+0x571021, 0x8c4240e8, 0x44102b, 0x14400009, 
+0x24020001, 0x3c030080, 0x3c010001, 0x370821, 
+0xac2040e8, 0x3c010001, 0x370821, 0x1000000c, 
+0xa02240f0, 0x3c020001, 0x571021, 0x904240f0, 
+0x14400006, 0x3c020080, 0x3c020001, 0x571021, 
+0x904240f1, 0x10400002, 0x3c020080, 0x621825, 
+0x8c040230, 0x10800013, 0x0, 0x3c020001, 
+0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, 
+0x370821, 0xac2240ec, 0x3c020001, 0x571021, 
+0x8c4240ec, 0x44102b, 0x14400006, 0x0, 
+0x3c010001, 0x370821, 0xac2040ec, 0x10000006, 
+0x781825, 0x3c020001, 0x571021, 0x904240f2, 
+0x54400001, 0x781825, 0x1060ff1a, 0x0, 
+0x8f420000, 0x10400007, 0x0, 0xaf80004c, 
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 
+0x0, 0x8f820060, 0x431025, 0xaf820060, 
+0x8f420000, 0x10400003, 0x0, 0x1000ff05, 
+0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, 
+0x0, 0x0, 0x0, 0x3c020001, 
+0x8c423d18, 0x27bdffe8, 0xafbf0014, 0x14400012, 
+0xafb00010, 0x3c100001, 0x26103f30, 0x2002021, 
+0xc002a28, 0x24052000, 0x26021fe0, 0x3c010001, 
+0xac223e98, 0x3c010001, 0xac223e94, 0xac020250, 
 0x24022000, 0xac100254, 0xac020258, 0x24020001, 
-0x3c010001, 0xac223db8, 0x8fbf0014, 0x8fb00010, 
-0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293f38, 
+0x3c010001, 0xac223d18, 0x8fbf0014, 0x8fb00010, 
+0x3e00008, 0x27bd0018, 0x3c090001, 0x8d293e98, 
 0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, 
 0x8c820004, 0xad250008, 0xad220004, 0x8f820054, 
 0xad260010, 0xad270014, 0xad230018, 0xad28001c, 
-0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423fd0, 
+0xad22000c, 0x2529ffe0, 0x3c020001, 0x24423f30, 
 0x122102b, 0x10400003, 0x0, 0x3c090001, 
-0x8d293f34, 0x3c020001, 0x8c423da0, 0xad220000, 
-0x3c020001, 0x8c423da0, 0x3c010001, 0xac293f38, 
+0x8d293e94, 0x3c020001, 0x8c423d00, 0xad220000, 
+0x3c020001, 0x8c423d00, 0x3c010001, 0xac293e98, 
 0xad220004, 0xac090250, 0x3e00008, 0x0, 
-0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103f38, 
-0x3c020001, 0x8c423da0, 0xafb10014, 0x808821, 
+0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e103e98, 
+0x3c020001, 0x8c423d00, 0xafb10014, 0x808821, 
 0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, 
 0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, 
-0xae020000, 0x3c020001, 0x8c423da0, 0xc09821, 
+0xae020000, 0x3c020001, 0x8c423d00, 0xc09821, 
 0xe0a821, 0x10800006, 0xae020004, 0x26050008, 
-0xc002a7b, 0x24060018, 0x10000005, 0x2610ffe0, 
-0x26040008, 0xc002a70, 0x24050018, 0x2610ffe0, 
-0x3c030001, 0x24633fd0, 0x203102b, 0x10400003, 
-0x0, 0x3c100001, 0x8e103f34, 0x8e220000, 
+0xc002a33, 0x24060018, 0x10000005, 0x2610ffe0, 
+0x26040008, 0xc002a28, 0x24050018, 0x2610ffe0, 
+0x3c030001, 0x24633f30, 0x203102b, 0x10400003, 
+0x0, 0x3c100001, 0x8e103e94, 0x8e220000, 
 0xae020000, 0x8e220004, 0xae120008, 0xae020004, 
 0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, 
 0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, 
 0x203102b, 0x10400003, 0x0, 0x3c100001, 
-0x8e103f34, 0x3c020001, 0x8c423da0, 0xae020000, 
-0x3c020001, 0x8c423da0, 0x3c010001, 0xac303f38, 
+0x8e103e94, 0x3c020001, 0x8c423d00, 0xae020000, 
+0x3c020001, 0x8c423d00, 0x3c010001, 0xac303e98, 
 0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, 
 0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, 
@@ -6342,8 +6334,8 @@
 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, 
-0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, 
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 
+0x8f820128, 0x3c040001, 0x24843844, 0xafa20014, 
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029bb, 
 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 
 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 
 0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, 
@@ -6352,8 +6344,8 @@
 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x14400011, 0x24020001, 0x3c010001, 0x370821, 
 0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, 
-0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, 
-0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, 
+0x3c040001, 0x24843838, 0xafa20014, 0x8f46002c, 
+0x8f870120, 0x3c050009, 0xc0029bb, 0x34a50900, 
 0x1000000f, 0x0, 0x8f4202f0, 0x24420001, 
 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 
 0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, 
@@ -6381,7 +6373,7 @@
 0x441021, 0xaf420358, 0x3c020800, 0x2c21024, 
 0x5040001a, 0x36940040, 0x10000018, 0x0, 
 0x30a20100, 0x10400015, 0x0, 0x3c020001, 
-0x8c423d64, 0x1040000c, 0x0, 0x274301b0, 
+0x8c423cc4, 0x1040000c, 0x0, 0x274301b0, 
 0x24650400, 0x65102b, 0x10400007, 0x26e40028, 
 0x8c820000, 0xac620000, 0x24630004, 0x65102b, 
 0x1440fffb, 0x24840004, 0x8f4202cc, 0xa34005b6, 
@@ -6414,8 +6406,8 @@
 0x431021, 0x904c0009, 0x318900ff, 0x39230006, 
 0x3182b, 0x39220011, 0x2102b, 0x621824, 
 0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, 
-0x248438f4, 0xafa20010, 0x8f4200a0, 0x34a54600, 
-0x1203821, 0xc002a03, 0xafa20014, 0x1000004e, 
+0x24843854, 0xafa20010, 0x8f4200a0, 0x34a54600, 
+0x1203821, 0xc0029bb, 0xafa20014, 0x1000004e, 
 0x0, 0x32c20004, 0x14400013, 0x2821, 
 0x316200ff, 0x14400004, 0x0, 0x95020002, 
 0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, 
@@ -6513,8 +6505,8 @@
 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
 0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, 
-0x8f820128, 0x3c040001, 0x248438e4, 0xafa20014, 
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002a03, 
+0x8f820128, 0x3c040001, 0x24843844, 0xafa20014, 
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc0029bb, 
 0x34a51100, 0x10000036, 0x0, 0x8f4202f0, 
 0x8f43002c, 0x24420001, 0xaf4202f0, 0x8f4202f0, 
 0x24020001, 0xa34205b2, 0x10000026, 0xaf430038, 
@@ -6523,8 +6515,8 @@
 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x14400011, 0x24020001, 0x3c010001, 0x370821, 
 0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, 
-0x3c040001, 0x248438d8, 0xafa20014, 0x8f46002c, 
-0x8f870120, 0x3c050009, 0xc002a03, 0x34a50900, 
+0x3c040001, 0x24843838, 0xafa20014, 0x8f46002c, 
+0x8f870120, 0x3c050009, 0xc0029bb, 0x34a50900, 
 0x1000000f, 0x0, 0x8f4202f0, 0x24420001, 
 0xaf4202f0, 0x8f4202f0, 0x8f42002c, 0xa34005b2, 
 0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, 
@@ -6554,785 +6546,750 @@
 0x32420048, 0x10400007, 0x24150001, 0x8e22001c, 
 0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd78, 
 0xae22001c, 0x32420100, 0x10400015, 0x0, 
-0x3c020001, 0x8c423d64, 0x1040000c, 0x0, 
+0x3c020001, 0x8c423cc4, 0x1040000c, 0x0, 
 0x274301b0, 0x24650400, 0x65102b, 0x10400007, 
 0x26e40028, 0x8c820000, 0xac620000, 0x24630004, 
 0x65102b, 0x1440fffb, 0x24840004, 0x8f4202cc, 
 0xa34005b6, 0x24420001, 0xaf4202cc, 0x8f4202cc, 
 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 
 0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, 
-0x27bd0058, 0x3e00008, 0x0, 0x8f8600e4, 
-0x8f8200e0, 0x2403fff8, 0x431024, 0x10c20007, 
-0x803821, 0x8cc20000, 0x8cc30004, 0xace20000, 
-0xace30004, 0x10000002, 0x24020001, 0x1021, 
-0x3e00008, 0x0, 0x3e00008, 0x0, 
-0x8f8300e4, 0x27623ff8, 0x14620002, 0x24620008, 
-0x27623000, 0x401821, 0xaf8300e8, 0xaf8300e4, 
-0x3e00008, 0x0, 0x3e00008, 0x0, 
-0x8f8400e0, 0x8f8800c4, 0x8f8300e8, 0x2402fff8, 
-0x823824, 0xe32023, 0x2c821000, 0x50400001, 
-0x24841000, 0x420c2, 0x801821, 0x8f440248, 
-0x8f45024c, 0x1021, 0xa32821, 0xa3302b, 
-0x822021, 0x862021, 0xaf440248, 0xaf45024c, 
-0x8f8300c8, 0x8f42013c, 0x1032023, 0x82102b, 
-0x14400004, 0x801821, 0x8f42013c, 0x822021, 
-0x801821, 0x8f440240, 0x8f450244, 0x1021, 
-0xa32821, 0xa3302b, 0x822021, 0x862021, 
-0xaf440240, 0xaf450244, 0xaf8800c8, 0xaf8700e4, 
-0xaf8700e8, 0x3e00008, 0x0, 0x27bdff30, 
-0x240a0001, 0xafbf00c8, 0xafbe00c4, 0xafb500c0, 
-0xafb300bc, 0xafb200b8, 0xafb100b4, 0xafb000b0, 
-0xa3a00097, 0xafa00044, 0xafaa005c, 0x934205b5, 
-0xa7a0008e, 0x1040000a, 0xa7a00086, 0x8f4b00c4, 
-0xafab0064, 0x8f4a00c0, 0xafaa006c, 0x8f4b00cc, 
-0xafab0074, 0x8f4a00c8, 0x10000125, 0xafaa007c, 
-0x8f420114, 0x40f809, 0x27a40020, 0x304200ff, 
-0x1040033b, 0x0, 0x8fab0024, 0x8faa0020, 
-0x3162ffff, 0x2442fffc, 0xafa2006c, 0x3c020006, 
-0x2c21024, 0xafab007c, 0x14400015, 0xafaa0064, 
-0x91420000, 0x30420001, 0x10400011, 0x2402ffff, 
-0x8d430000, 0x14620004, 0x3402ffff, 0x95430004, 
-0x1062000b, 0x0, 0xc002343, 0x8fa40064, 
-0x304200ff, 0x14400006, 0x0, 0x8f420118, 
-0x40f809, 0x0, 0x1000031d, 0x0, 
-0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, 
-0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, 
-0x10000040, 0x1821, 0x3c020080, 0x621024, 
-0x10400007, 0x0, 0x8f42037c, 0x24420001, 
-0xaf42037c, 0x8f42037c, 0x10000036, 0x24030001, 
-0x8f420200, 0x24420001, 0xaf420200, 0x8f420200, 
-0x3c020001, 0x621024, 0x10400006, 0x3c020002, 
-0x8f4201b4, 0x24420001, 0xaf4201b4, 0x8f4201b4, 
-0x3c020002, 0x621024, 0x10400006, 0x3c020004, 
-0x8f42036c, 0x24420001, 0xaf42036c, 0x8f42036c, 
-0x3c020004, 0x621024, 0x10400006, 0x3c020008, 
-0x8f420370, 0x24420001, 0xaf420370, 0x8f420370, 
-0x3c020008, 0x621024, 0x10400006, 0x3c020010, 
-0x8f420374, 0x24420001, 0xaf420374, 0x8f420374, 
-0x3c020010, 0x621024, 0x10400006, 0x3c020020, 
-0x8f4201b0, 0x24420001, 0xaf4201b0, 0x8f4201b0, 
-0x3c020020, 0x621024, 0x10400006, 0x24030001, 
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, 
-0x24030001, 0x8c020260, 0x8fab006c, 0x4b102b, 
-0x10400014, 0x307000ff, 0x8f4201d8, 0x24420001, 
-0xaf4201d8, 0x8f4201d8, 0x8faa007c, 0x8f8200e0, 
-0x354a0100, 0xafaa007c, 0xafa20010, 0x8f8200e4, 
-0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, 
-0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, 
-0x34a50800, 0x12000010, 0x3c020080, 0x2c21024, 
-0x1440000e, 0x32c20400, 0x8fab007c, 0x3c020080, 
-0x34420100, 0x1621024, 0x10400005, 0x0, 
-0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, 
-0x100002a0, 0x8fa3006c, 0x32c20400, 0x10400015, 
-0x34028100, 0x8faa0064, 0x9543000c, 0x14620012, 
-0x3c020100, 0x240b0200, 0xa7ab008e, 0x9542000e, 
-0x8d430008, 0x8d440004, 0x8d450000, 0x8faa006c, 
-0x8fab0064, 0x254afffc, 0xafaa006c, 0xa7a20086, 
-0xad63000c, 0xad640008, 0xad650004, 0x256b0004, 
-0xafab0064, 0x3c020100, 0x2c21024, 0x10400004, 
-0x0, 0x8faa006c, 0x254a0004, 0xafaa006c, 
-0x8f4200bc, 0x5040000a, 0xafa00074, 0x8fab006c, 
-0x4b102b, 0x50400006, 0xafa00074, 0x8f4200bc, 
-0x1621023, 0xafa20074, 0x8f4a00bc, 0xafaa006c, 
-0x8f420080, 0x8fab006c, 0x4b102b, 0x10400056, 
-0x32c28000, 0x1040005e, 0x240a0003, 0x32c21000, 
-0x1040005b, 0xafaa005c, 0x10000058, 0x240b0004, 
-0x8f420340, 0x2403ffbf, 0x283a024, 0x24420001, 
-0xaf420340, 0x1000023f, 0x8f420340, 0x2c2b025, 
-0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, 
-0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, 
-0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 
-0x34a52250, 0x1000022f, 0x0, 0x2c2b025, 
-0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, 
-0x248439e4, 0x24020002, 0xafa20014, 0xafa30010, 
-0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 
-0x34a52450, 0x1000021f, 0x0, 0x8ea20000, 
-0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, 
-0xafbe0014, 0x8ea70018, 0x34a52800, 0xc002a03, 
-0x603021, 0x10000213, 0x0, 0xa6b1000a, 
-0x8f820124, 0x3c040001, 0x24843a04, 0xafbe0014, 
-0xafa20010, 0x8f460044, 0x8f870120, 0x3c050007, 
-0xc002a03, 0x34a53000, 0x10000206, 0x0, 
-0xa6b1000a, 0xa6b2000e, 0x8f820124, 0x3c040001, 
-0x24843a10, 0xafbe0014, 0xafa20010, 0x8f460044, 
-0x8f870120, 0x3c050007, 0xc002a03, 0x34a53200, 
-0x100001f8, 0x0, 0x8f420084, 0x8faa006c, 
-0x4a102b, 0x14400007, 0x3c020001, 0x2c21024, 
-0x10400004, 0x0, 0x240b0002, 0xafab005c, 
-0x8faa006c, 0x1140020b, 0x27ab0020, 0xafab00a4, 
-0x3c0a001f, 0x354affff, 0xafaa009c, 0x8fab005c, 
-0x240a0001, 0x156a0021, 0x24020002, 0x8f430054, 
-0x8f420050, 0x1062000b, 0x274b0054, 0x8f5e0054, 
-0x3403ecc0, 0xafab004c, 0x27c20001, 0x304201ff, 
-0xafa20054, 0x1e1140, 0x431021, 0x1000006b, 
+0x27bd0058, 0x3e00008, 0x0, 0x8f8400e0, 
+0x8f8800c4, 0x8f8300e8, 0x2402fff8, 0x823824, 
+0xe32023, 0x2c821000, 0x50400001, 0x24841000, 
+0x420c2, 0x801821, 0x8f440248, 0x8f45024c, 
+0x1021, 0xa32821, 0xa3302b, 0x822021, 
+0x862021, 0xaf440248, 0xaf45024c, 0x8f8300c8, 
+0x8f42013c, 0x1032023, 0x82102b, 0x14400004, 
+0x801821, 0x8f42013c, 0x822021, 0x801821, 
+0x8f440240, 0x8f450244, 0x1021, 0xa32821, 
+0xa3302b, 0x822021, 0x862021, 0xaf440240, 
+0xaf450244, 0xaf8800c8, 0xaf8700e4, 0xaf8700e8, 
+0x3e00008, 0x0, 0x27bdff30, 0x240a0001, 
+0xafbf00c8, 0xafbe00c4, 0xafb500c0, 0xafb300bc, 
+0xafb200b8, 0xafb100b4, 0xafb000b0, 0xa3a00097, 
+0xafa00044, 0xafaa005c, 0x934205b5, 0xa7a0008e, 
+0x1040000a, 0xa7a00086, 0x8f4b00c4, 0xafab0064, 
+0x8f4a00c0, 0xafaa006c, 0x8f4b00cc, 0xafab0074, 
+0x8f4a00c8, 0x10000129, 0xafaa007c, 0x8f420114, 
+0x40f809, 0x0, 0x403021, 0x10c0033f, 
+0x0, 0x8cc20000, 0x8cc30004, 0xafa20020, 
+0xafa30024, 0x8fab0024, 0x8faa0020, 0x3162ffff, 
+0x2442fffc, 0xafa2006c, 0x3c020006, 0x2c21024, 
+0xafab007c, 0x14400015, 0xafaa0064, 0x91420000, 
+0x30420001, 0x10400011, 0x2402ffff, 0x8d430000, 
+0x14620004, 0x3402ffff, 0x95430004, 0x1062000b, 
+0x0, 0xc00233b, 0x8fa40064, 0x304200ff, 
+0x14400006, 0x0, 0x8f420118, 0x40f809, 
+0x0, 0x1000031d, 0x0, 0x8fa20024, 
+0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, 
+0x431824, 0x14600003, 0xafa20024, 0x10000040, 
+0x1821, 0x3c020080, 0x621024, 0x10400007, 
+0x0, 0x8f42037c, 0x24420001, 0xaf42037c, 
+0x8f42037c, 0x10000036, 0x24030001, 0x8f420200, 
+0x24420001, 0xaf420200, 0x8f420200, 0x3c020001, 
+0x621024, 0x10400006, 0x3c020002, 0x8f4201b4, 
+0x24420001, 0xaf4201b4, 0x8f4201b4, 0x3c020002, 
+0x621024, 0x10400006, 0x3c020004, 0x8f42036c, 
+0x24420001, 0xaf42036c, 0x8f42036c, 0x3c020004, 
+0x621024, 0x10400006, 0x3c020008, 0x8f420370, 
+0x24420001, 0xaf420370, 0x8f420370, 0x3c020008, 
+0x621024, 0x10400006, 0x3c020010, 0x8f420374, 
+0x24420001, 0xaf420374, 0x8f420374, 0x3c020010, 
+0x621024, 0x10400006, 0x3c020020, 0x8f4201b0, 
+0x24420001, 0xaf4201b0, 0x8f4201b0, 0x3c020020, 
+0x621024, 0x10400006, 0x24030001, 0x8f420378, 
+0x24420001, 0xaf420378, 0x8f420378, 0x24030001, 
+0x8c020260, 0x8fab006c, 0x4b102b, 0x10400014, 
+0x307000ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, 
+0x8f4201d8, 0x8faa007c, 0x8f8200e0, 0x354a0100, 
+0xafaa007c, 0xafa20010, 0x8f8200e4, 0x24100001, 
+0x3c040001, 0x24843914, 0xafa20014, 0x8fa60020, 
+0x8fa70024, 0x3c050007, 0xc0029bb, 0x34a50800, 
+0x12000010, 0x3c020080, 0x2c21024, 0x1440000e, 
+0x32c20400, 0x8fab007c, 0x3c020080, 0x34420100, 
+0x1621024, 0x10400005, 0x0, 0x8f4201fc, 
+0x24420001, 0xaf4201fc, 0x8f4201fc, 0x100002a0, 
+0x8fa3006c, 0x32c20400, 0x10400015, 0x34028100, 
+0x8faa0064, 0x9543000c, 0x14620012, 0x3c020100, 
+0x240b0200, 0xa7ab008e, 0x9542000e, 0x8d430008, 
+0x8d440004, 0x8d450000, 0x8faa006c, 0x8fab0064, 
+0x254afffc, 0xafaa006c, 0xa7a20086, 0xad63000c, 
+0xad640008, 0xad650004, 0x256b0004, 0xafab0064, 
+0x3c020100, 0x2c21024, 0x10400004, 0x0, 
+0x8faa006c, 0x254a0004, 0xafaa006c, 0x8f4200bc, 
+0x5040000a, 0xafa00074, 0x8fab006c, 0x4b102b, 
+0x50400006, 0xafa00074, 0x8f4200bc, 0x1621023, 
+0xafa20074, 0x8f4a00bc, 0xafaa006c, 0x8f420080, 
+0x8fab006c, 0x4b102b, 0x10400056, 0x32c28000, 
+0x1040005e, 0x240a0003, 0x32c21000, 0x1040005b, 
+0xafaa005c, 0x10000058, 0x240b0004, 0x8f420340, 
+0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, 
+0x1000023f, 0x8f420340, 0x2c2b025, 0x2402ffbf, 
+0x282a024, 0x8f830128, 0x3c040001, 0x24843944, 
+0x26620001, 0xafa20014, 0xafa30010, 0x8f860120, 
+0x8f870124, 0x3c050007, 0xc0029bb, 0x34a52250, 
+0x1000022f, 0x0, 0x2c2b025, 0x2402ffbf, 
+0x282a024, 0x8f830128, 0x3c040001, 0x24843944, 
+0x24020002, 0xafa20014, 0xafa30010, 0x8f860120, 
+0x8f870124, 0x3c050007, 0xc0029bb, 0x34a52450, 
+0x1000021f, 0x0, 0x8ea20000, 0x8ea30004, 
+0x3c040001, 0x2484395c, 0xafb00010, 0xafbe0014, 
+0x8ea70018, 0x34a52800, 0xc0029bb, 0x603021, 
+0x10000213, 0x0, 0xa6b1000a, 0x8f820124, 
+0x3c040001, 0x24843964, 0xafbe0014, 0xafa20010, 
+0x8f460044, 0x8f870120, 0x3c050007, 0xc0029bb, 
+0x34a53000, 0x10000206, 0x0, 0xa6b1000a, 
+0xa6b2000e, 0x8f820124, 0x3c040001, 0x24843970, 
+0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120, 
+0x3c050007, 0xc0029bb, 0x34a53200, 0x100001f8, 
+0x0, 0x8f420084, 0x8faa006c, 0x4a102b, 
+0x14400007, 0x3c020001, 0x2c21024, 0x10400004, 
+0x0, 0x240b0002, 0xafab005c, 0x8faa006c, 
+0x1140020b, 0x27ab0020, 0xafab00a4, 0x3c0a001f, 
+0x354affff, 0xafaa009c, 0x8fab005c, 0x240a0001, 
+0x156a0021, 0x24020002, 0x8f430054, 0x8f420050, 
+0x1062000b, 0x274b0054, 0x8f5e0054, 0x3403ecc0, 
+0xafab004c, 0x27c20001, 0x304201ff, 0xafa20054, 
+0x1e1140, 0x431021, 0x1000006b, 0x2e2a821, 
+0x8f420044, 0x8faa006c, 0x3c040001, 0x24843920, 
+0xafaa0014, 0xafa20010, 0x8f460054, 0x8f470050, 
+0x3c050007, 0xc0029bb, 0x34a51300, 0x8f430340, 
+0x2402ffbf, 0x282a024, 0x24630001, 0xaf430340, 
+0x100001c3, 0x8f420340, 0x1562001d, 0x0, 
+0x8f430074, 0x8f420070, 0x1062000a, 0x274a0074, 
+0x8f5e0074, 0xafaa004c, 0x27c20001, 0x304203ff, 
+0xafa20054, 0x1e1140, 0x24426cc0, 0x1000004a, 
+0x2e2a821, 0x8f420044, 0x8fab006c, 0x3c040001, 
+0x2484392c, 0x3c050007, 0xafab0014, 0xafa20010, 
+0x8f460074, 0x8f470070, 0x34a51500, 0x240a0001, 
+0xc0029bb, 0xafaa005c, 0x1000ffc3, 0x0, 
+0x8f430064, 0x8f420060, 0x1062001a, 0x274b0064, 
+0x8f5e0064, 0x8faa005c, 0xafab004c, 0x27c20001, 
+0x304200ff, 0xafa20054, 0x24020004, 0x1542000e, 
+0x1e1140, 0x1e1180, 0x24420cc0, 0x2e21021, 
+0xafa20044, 0x9442002a, 0x8fab0044, 0x8faa006c, 
+0x4a102b, 0x10400024, 0x25750020, 0x240b0001, 
+0x10000021, 0xa3ab0097, 0x24424cc0, 0x1000001e, 
 0x2e2a821, 0x8f420044, 0x8faa006c, 0x3c040001, 
-0x248439c0, 0xafaa0014, 0xafa20010, 0x8f460054, 
-0x8f470050, 0x3c050007, 0xc002a03, 0x34a51300, 
-0x8f430340, 0x2402ffbf, 0x282a024, 0x24630001, 
-0xaf430340, 0x100001c3, 0x8f420340, 0x1562001d, 
-0x0, 0x8f430074, 0x8f420070, 0x1062000a, 
-0x274a0074, 0x8f5e0074, 0xafaa004c, 0x27c20001, 
-0x304203ff, 0xafa20054, 0x1e1140, 0x24426cc0, 
-0x1000004a, 0x2e2a821, 0x8f420044, 0x8fab006c, 
-0x3c040001, 0x248439cc, 0x3c050007, 0xafab0014, 
-0xafa20010, 0x8f460074, 0x8f470070, 0x34a51500, 
-0x240a0001, 0xc002a03, 0xafaa005c, 0x1000ffc3, 
-0x0, 0x8f430064, 0x8f420060, 0x1062001a, 
-0x274b0064, 0x8f5e0064, 0x8faa005c, 0xafab004c, 
-0x27c20001, 0x304200ff, 0xafa20054, 0x24020004, 
-0x1542000e, 0x1e1140, 0x1e1180, 0x24420cc0, 
-0x2e21021, 0xafa20044, 0x9442002a, 0x8fab0044, 
-0x8faa006c, 0x4a102b, 0x10400024, 0x25750020, 
-0x240b0001, 0x10000021, 0xa3ab0097, 0x24424cc0, 
-0x1000001e, 0x2e2a821, 0x8f420044, 0x8faa006c, 
-0x3c040001, 0x248439d8, 0xafaa0014, 0xafa20010, 
-0x8f460064, 0x8f470060, 0x3c050007, 0xc002a03, 
-0x34a51800, 0x3c020008, 0x2c21024, 0x1440ff34, 
-0x0, 0x8f420360, 0x240b0001, 0xafab005c, 
-0x24420001, 0xaf420360, 0x1000ff90, 0x8f420360, 
-0x27a30036, 0x131040, 0x621821, 0x94620000, 
-0x441021, 0x10000020, 0xa4620000, 0x8faa0064, 
-0xaeaa0018, 0x93a20097, 0x10400072, 0x9821, 
-0x8fab0044, 0x8fa4006c, 0x8fa300a4, 0x25620020, 
-0xafa20028, 0x25620008, 0xafa20030, 0x25620010, 
-0xafab002c, 0xafa20034, 0x9562002a, 0xa7a20038, 
-0x95620018, 0xa7a2003a, 0x9562001a, 0xa7a2003c, 
-0x9562001c, 0xa7a2003e, 0x94620018, 0x24630002, 
-0x822023, 0x1880ffde, 0x26730001, 0x2e620004, 
-0x1440fff9, 0x0, 0x8f4200fc, 0x26650001, 
-0xa2102a, 0x1440002b, 0x24030001, 0x8f83012c, 
-0x10600023, 0x0, 0x8f820124, 0x431023, 
-0x22143, 0x58800001, 0x24840040, 0x8f820128, 
-0x431023, 0x21943, 0x58600001, 0x24630040, 
-0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 
-0x8f4200fc, 0xa2102a, 0x10400011, 0x24030001, 
-0x10000015, 0x306200ff, 0x8faa0064, 0x96070018, 
-0xafaa0010, 0x8e220008, 0x3c040001, 0x248439f0, 
-0x8c430004, 0x8c420000, 0x34a52400, 0x2403021, 
-0xc002a03, 0xafa30014, 0x1000002b, 0x0, 
-0x8f420324, 0x1821, 0x24420001, 0xaf420324, 
-0x8f420324, 0x306200ff, 0x5040fedc, 0x3c020800, 
-0x12600021, 0x9021, 0x8fb100a4, 0x2208021, 
-0x8e220008, 0x96070018, 0x8fa60064, 0x8c440000, 
-0x8c450004, 0x240b0001, 0xafab0010, 0xafbe0014, 
-0x8f420008, 0xafa20018, 0x8f42010c, 0x40f809, 
-0x0, 0x1040ffd8, 0x3c050007, 0x96020018, 
-0x8faa0064, 0x8fab009c, 0x1425021, 0x16a102b, 
-0x10400004, 0xafaa0064, 0x8f42013c, 0x1425023, 
-0xafaa0064, 0x26100002, 0x26520001, 0x253102b, 
-0x1440ffe3, 0x26310004, 0x8fb0006c, 0x10000036, 
-0x97b10038, 0x8f4200fc, 0x24050002, 0xa2102a, 
-0x1440001b, 0x24030001, 0x8f83012c, 0x10600013, 
+0x24843938, 0xafaa0014, 0xafa20010, 0x8f460064, 
+0x8f470060, 0x3c050007, 0xc0029bb, 0x34a51800, 
+0x3c020008, 0x2c21024, 0x1440ff34, 0x0, 
+0x8f420360, 0x240b0001, 0xafab005c, 0x24420001, 
+0xaf420360, 0x1000ff90, 0x8f420360, 0x27a30036, 
+0x131040, 0x621821, 0x94620000, 0x441021, 
+0x10000020, 0xa4620000, 0x8faa0064, 0xaeaa0018, 
+0x93a20097, 0x10400072, 0x9821, 0x8fab0044, 
+0x8fa4006c, 0x8fa300a4, 0x25620020, 0xafa20028, 
+0x25620008, 0xafa20030, 0x25620010, 0xafab002c, 
+0xafa20034, 0x9562002a, 0xa7a20038, 0x95620018, 
+0xa7a2003a, 0x9562001a, 0xa7a2003c, 0x9562001c, 
+0xa7a2003e, 0x94620018, 0x24630002, 0x822023, 
+0x1880ffde, 0x26730001, 0x2e620004, 0x1440fff9, 
+0x0, 0x8f4200fc, 0x26650001, 0xa2102a, 
+0x1440002b, 0x24030001, 0x8f83012c, 0x10600023, 
 0x0, 0x8f820124, 0x431023, 0x22143, 
 0x58800001, 0x24840040, 0x8f820128, 0x431023, 
 0x21943, 0x58600001, 0x24630040, 0x64102a, 
 0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, 
-0xa2102a, 0x14400006, 0x24030001, 0x8f420324, 
+0xa2102a, 0x10400011, 0x24030001, 0x10000015, 
+0x306200ff, 0x8faa0064, 0x96070018, 0xafaa0010, 
+0x8e220008, 0x3c040001, 0x24843950, 0x8c430004, 
+0x8c420000, 0x34a52400, 0x2403021, 0xc0029bb, 
+0xafa30014, 0x1000002b, 0x0, 0x8f420324, 
 0x1821, 0x24420001, 0xaf420324, 0x8f420324, 
-0x306200ff, 0x1040fea5, 0x3c020800, 0x96b1000a, 
-0x8fb0006c, 0x3223ffff, 0x70102b, 0x54400001, 
-0x608021, 0x8ea40000, 0x8ea50004, 0x240a0001, 
-0xafaa0010, 0xafbe0014, 0x8f420008, 0x8fa60064, 
-0xafa20018, 0x8f42010c, 0x40f809, 0x2003821, 
-0x1040fea2, 0x3c050007, 0x96a3000e, 0x97ab008e, 
-0x11600007, 0x609021, 0x934205b5, 0x14400004, 
-0x0, 0x97aa0086, 0x6b1825, 0xa6aa0016, 
-0x8fab007c, 0x3c02ffff, 0x1621024, 0x10400003, 
-0xb1402, 0x34630400, 0xa6a20014, 0x8faa006c, 
-0x560a0072, 0xa6a3000e, 0x34620004, 0xa6a2000e, 
-0x8fab0074, 0x14b1021, 0xa6a2000a, 0x8f430044, 
+0x306200ff, 0x5040fedc, 0x3c020800, 0x12600021, 
+0x9021, 0x8fb100a4, 0x2208021, 0x8e220008, 
+0x96070018, 0x8fa60064, 0x8c440000, 0x8c450004, 
+0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008, 
+0xafa20018, 0x8f42010c, 0x40f809, 0x0, 
+0x1040ffd8, 0x3c050007, 0x96020018, 0x8faa0064, 
+0x8fab009c, 0x1425021, 0x16a102b, 0x10400004, 
+0xafaa0064, 0x8f42013c, 0x1425023, 0xafaa0064, 
+0x26100002, 0x26520001, 0x253102b, 0x1440ffe3, 
+0x26310004, 0x8fb0006c, 0x10000036, 0x97b10038, 
+0x8f4200fc, 0x24050002, 0xa2102a, 0x1440001b, 
+0x24030001, 0x8f83012c, 0x10600013, 0x0, 
+0x8f820124, 0x431023, 0x22143, 0x58800001, 
+0x24840040, 0x8f820128, 0x431023, 0x21943, 
+0x58600001, 0x24630040, 0x64102a, 0x54400001, 
+0x602021, 0xaf4400fc, 0x8f4200fc, 0xa2102a, 
+0x14400006, 0x24030001, 0x8f420324, 0x1821, 
+0x24420001, 0xaf420324, 0x8f420324, 0x306200ff, 
+0x1040fea5, 0x3c020800, 0x96b1000a, 0x8fb0006c, 
+0x3223ffff, 0x70102b, 0x54400001, 0x608021, 
+0x8ea40000, 0x8ea50004, 0x240a0001, 0xafaa0010, 
+0xafbe0014, 0x8f420008, 0x8fa60064, 0xafa20018, 
+0x8f42010c, 0x40f809, 0x2003821, 0x1040fea2, 
+0x3c050007, 0x96a3000e, 0x97ab008e, 0x11600007, 
+0x609021, 0x934205b5, 0x14400004, 0x0, 
+0x97aa0086, 0x6b1825, 0xa6aa0016, 0x8fab007c, 
+0x3c02ffff, 0x1621024, 0x10400003, 0xb1402, 
+0x34630400, 0xa6a20014, 0x8faa006c, 0x560a0072, 
+0xa6a3000e, 0x34620004, 0xa6a2000e, 0x8fab0074, 
+0x14b1021, 0xa6a2000a, 0x8f430044, 0x8f440190, 
+0x8f450194, 0x34028000, 0xafa20010, 0x8f420044, 
+0x2a03021, 0x24070020, 0xafa20014, 0x8f42000c, 
+0x31940, 0x604821, 0xafa20018, 0x8f42010c, 
+0x4021, 0xa92821, 0xa9182b, 0x882021, 
+0x40f809, 0x832021, 0x5040fe7f, 0xa6b2000e, 
+0x8f420358, 0xafa0006c, 0xa34005b5, 0x2442ffff, 
+0xaf420358, 0x8faa005c, 0x240b0001, 0x8f420358, 
+0x154b0006, 0x24020002, 0x8f42034c, 0x2442ffff, 
+0xaf42034c, 0x1000000c, 0x8f42034c, 0x15420006, 
+0x0, 0x8f420354, 0x2442ffff, 0xaf420354, 
+0x10000005, 0x8f420354, 0x8f420350, 0x2442ffff, 
+0xaf420350, 0x8f420350, 0x8faa0054, 0x8fab004c, 
+0xad6a0000, 0x8f420044, 0x8f440088, 0x8f430078, 
+0x24420001, 0x441024, 0x24630001, 0xaf420044, 
+0xaf430078, 0x8c020240, 0x62182b, 0x14600065, 
+0x24070008, 0x8f440158, 0x8f45015c, 0x8f430044, 
+0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010, 
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
+0x24c6001c, 0x14400011, 0x240b0001, 0x3c010001, 
+0x370821, 0xa02b40f2, 0x8f820124, 0xafa20010, 
+0x8f820128, 0x3c040001, 0x2484390c, 0xafa20014, 
+0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb, 
+0x34a51300, 0x1000000b, 0x0, 0x8f4202f4, 
+0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 
+0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 
+0xaf400078, 0x8f420308, 0x24420001, 0xaf420308, 
+0x10000038, 0x8f420308, 0xa6b0000a, 0x8f430044, 
 0x8f440190, 0x8f450194, 0x34028000, 0xafa20010, 
 0x8f420044, 0x2a03021, 0x24070020, 0xafa20014, 
 0x8f42000c, 0x31940, 0x604821, 0xafa20018, 
 0x8f42010c, 0x4021, 0xa92821, 0xa9182b, 
-0x882021, 0x40f809, 0x832021, 0x5040fe7f, 
-0xa6b2000e, 0x8f420358, 0xafa0006c, 0xa34005b5, 
-0x2442ffff, 0xaf420358, 0x8faa005c, 0x240b0001, 
-0x8f420358, 0x154b0006, 0x24020002, 0x8f42034c, 
-0x2442ffff, 0xaf42034c, 0x1000000c, 0x8f42034c, 
-0x15420006, 0x0, 0x8f420354, 0x2442ffff, 
-0xaf420354, 0x10000005, 0x8f420354, 0x8f420350, 
-0x2442ffff, 0xaf420350, 0x8f420350, 0x8faa0054, 
-0x8fab004c, 0xad6a0000, 0x8f420044, 0x8f440088, 
-0x8f430078, 0x24420001, 0x441024, 0x24630001, 
-0xaf420044, 0xaf430078, 0x8c020240, 0x62182b, 
-0x14600065, 0x24070008, 0x8f440158, 0x8f45015c, 
-0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, 
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 
-0x40f809, 0x24c6001c, 0x14400011, 0x240b0001, 
-0x3c010001, 0x370821, 0xa02b40f2, 0x8f820124, 
-0xafa20010, 0x8f820128, 0x3c040001, 0x248439ac, 
-0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, 
-0xc002a03, 0x34a51300, 0x1000000b, 0x0, 
-0x8f4202f4, 0x24420001, 0xaf4202f4, 0x8f4202f4, 
-0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, 
-0xa02040f2, 0xaf400078, 0x8f420308, 0x24420001, 
-0xaf420308, 0x10000038, 0x8f420308, 0xa6b0000a, 
-0x8f430044, 0x8f440190, 0x8f450194, 0x34028000, 
-0xafa20010, 0x8f420044, 0x2a03021, 0x24070020, 
-0xafa20014, 0x8f42000c, 0x31940, 0x604821, 
-0xafa20018, 0x8f42010c, 0x4021, 0xa92821, 
-0xa9182b, 0x882021, 0x40f809, 0x832021, 
-0x1040fe1f, 0x240a0001, 0xa34a05b5, 0x8fab006c, 
-0x8faa0064, 0x1705823, 0xafab006c, 0x8fab009c, 
-0x1505021, 0x16a102b, 0x10400004, 0xafaa0064, 
-0x8f42013c, 0x1425023, 0xafaa0064, 0x8f420358, 
-0x2442ffff, 0xaf420358, 0x8f420358, 0x8f42034c, 
-0x2442ffff, 0xaf42034c, 0x8fab0054, 0x8faa004c, 
-0x8f42034c, 0xad4b0000, 0x8f420044, 0x8f440088, 
-0x8f430078, 0x24420001, 0x441024, 0x24630001, 
-0xaf420044, 0xaf430078, 0x8faa006c, 0x1540fe1b, 
-0x0, 0x8fab006c, 0x1160001e, 0x0, 
-0x934205b5, 0x10400009, 0x0, 0x8faa0064, 
-0xaf4a00c4, 0xaf4b00c0, 0x8fab007c, 0xaf4b00c8, 
-0x8faa0074, 0x1000000e, 0xaf4a00cc, 0x97ab008e, 
-0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, 
-0xa443000c, 0x97aa0086, 0x8c440004, 0x8c450008, 
-0xa44a000e, 0xac440000, 0xac450004, 0xac460008, 
-0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, 
-0x8f42033c, 0x8fab007c, 0x3164ffff, 0x2484fffc, 
-0x801821, 0x8f440240, 0x8f450244, 0x8f460118, 
-0x1021, 0xa32821, 0xa3382b, 0x822021, 
-0x872021, 0xaf440240, 0xc0f809, 0xaf450244, 
-0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0, 0x8fb300bc, 
-0x8fb200b8, 0x8fb100b4, 0x8fb000b0, 0x3e00008, 
-0x27bd00d0, 0x3e00008, 0x0, 0x27bdff38, 
-0x240b0001, 0xafbf00c0, 0xafbe00bc, 0xafb500b8, 
-0xafb300b4, 0xafb200b0, 0xafb100ac, 0xafb000a8, 
-0xa3a00087, 0xafa00044, 0xafab005c, 0x934205b5, 
-0xa7a00076, 0x10400007, 0xa7a0007e, 0x8f4c00c0, 
-0xafac0064, 0x8f4b00c8, 0x8f5e00c4, 0x10000129, 
-0xafab006c, 0x8f420114, 0x40f809, 0x27a40020, 
-0x304200ff, 0x1040029a, 0x0, 0x8fac0024, 
-0x8fbe0020, 0x3182ffff, 0x2442fffc, 0xafa20064, 
-0x3c020006, 0x2c21024, 0x14400015, 0xafac006c, 
-0x93c20000, 0x30420001, 0x10400011, 0x2402ffff, 
-0x8fc30000, 0x14620004, 0x3402ffff, 0x97c30004, 
-0x1062000b, 0x0, 0xc002343, 0x3c02021, 
-0x304200ff, 0x14400006, 0x0, 0x8f420118, 
-0x40f809, 0x0, 0x1000027d, 0x0, 
-0x8fa20024, 0x3c03ffbf, 0x3463ffff, 0x431024, 
-0x3c03ffff, 0x431824, 0x14600003, 0xafa20024, 
-0x10000040, 0x8021, 0x3c020080, 0x621024, 
-0x10400007, 0x0, 0x8f42037c, 0x24420001, 
-0xaf42037c, 0x8f42037c, 0x10000036, 0x24100001, 
-0x8f420200, 0x24420001, 0xaf420200, 0x8f420200, 
-0x3c020001, 0x621024, 0x10400006, 0x3c020002, 
-0x8f4201b4, 0x24420001, 0xaf4201b4, 0x8f4201b4, 
-0x3c020002, 0x621024, 0x10400006, 0x3c020004, 
-0x8f42036c, 0x24420001, 0xaf42036c, 0x8f42036c, 
-0x3c020004, 0x621024, 0x10400006, 0x3c020008, 
-0x8f420370, 0x24420001, 0xaf420370, 0x8f420370, 
-0x3c020008, 0x621024, 0x10400006, 0x3c020010, 
-0x8f420374, 0x24420001, 0xaf420374, 0x8f420374, 
-0x3c020010, 0x621024, 0x10400006, 0x3c020020, 
-0x8f4201b0, 0x24420001, 0xaf4201b0, 0x8f4201b0, 
-0x3c020020, 0x621024, 0x10400006, 0x24100001, 
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, 
-0x24100001, 0x8c020260, 0x8fab0064, 0x4b102b, 
-0x10400015, 0x320200ff, 0x8f4201d8, 0x24420001, 
-0xaf4201d8, 0x8f4201d8, 0x8fac006c, 0x8f8200e0, 
-0x358c0100, 0xafac006c, 0xafa20010, 0x8f8200e4, 
-0x24100001, 0x3c040001, 0x248439b4, 0xafa20014, 
-0x8fa60020, 0x8fa70024, 0x3c050007, 0xc002a03, 
-0x34a53600, 0x320200ff, 0x10400010, 0x3c020080, 
-0x2c21024, 0x1440000e, 0x32c20400, 0x8fab006c, 
-0x3c020080, 0x34420100, 0x1621024, 0x10400005, 
-0x0, 0x8f4201fc, 0x24420001, 0xaf4201fc, 
-0x8f4201fc, 0x100001ff, 0x8fa30064, 0x32c20400, 
-0x10400012, 0x34028100, 0x97c3000c, 0x1462000f, 
-0x0, 0x240c0200, 0xa7ac0076, 0x97c2000e, 
-0x8fc30008, 0x8fc40004, 0x8fab0064, 0x8fc50000, 
-0x256bfffc, 0xafab0064, 0xa7a2007e, 0xafc3000c, 
-0xafc40008, 0xafc50004, 0x27de0004, 0x8fa70064, 
-0x320200ff, 0x14400031, 0x3c020100, 0x97c3000c, 
-0x2c6205dd, 0x10400015, 0x2821, 0x32c20800, 
-0x10400015, 0x24020800, 0x97c30014, 0x14620012, 
-0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021, 
-0x97c30010, 0x24020300, 0x14620004, 0x801021, 
-0x97c20012, 0x2c440001, 0x801021, 0x54400006, 
-0x24050016, 0x10000004, 0x0, 0x24020800, 
-0x50620001, 0x2405000e, 0x10a00013, 0x3c52021, 
-0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b, 
-0x10400003, 0x0, 0x8f42013c, 0x621823, 
-0x90620000, 0x38430006, 0x2c630001, 0x38420011, 
-0x2c420001, 0x621825, 0x10600004, 0x3c020100, 
-0x94820002, 0x453821, 0x3c020100, 0x2c21024, 
-0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, 
-0x3c050007, 0x3c040001, 0x24843a1c, 0x8fa60064, 
-0x34a54000, 0xafa00010, 0xc002a03, 0xafa00014, 
-0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, 
-0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, 
-0x10400034, 0x240b0003, 0x32c21000, 0x10400031, 
-0xafab005c, 0x1000002e, 0x240c0004, 0x8f420340, 
-0x2403ffbf, 0x283a024, 0x24420001, 0xaf420340, 
-0x10000173, 0x8f420340, 0x3c020800, 0x2c2b025, 
-0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, 
-0x248439e4, 0x26620001, 0xafa20014, 0xafa30010, 
-0x8f860120, 0x8f870124, 0x3c050007, 0xc002a03, 
-0x34a55300, 0x10000162, 0x0, 0x8ea20000, 
-0x8ea30004, 0x3c040001, 0x248439fc, 0xafb00010, 
-0xafb10014, 0x8ea70018, 0x34a55900, 0xc002a03, 
-0x603021, 0x10000156, 0x0, 0x8f420084, 
-0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, 
-0x2c21024, 0x10400004, 0x0, 0x240c0002, 
-0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020, 
-0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021, 
-0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b, 
-0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c, 
-0x26220001, 0x304201ff, 0xafa20054, 0x111140, 
-0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, 
-0x8fac0064, 0x3c040001, 0x248439c0, 0xafac0014, 
-0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, 
-0xc002a03, 0x34a54300, 0x8f430340, 0x2402ffbf, 
-0x282a024, 0x24630001, 0xaf430340, 0x10000124, 
-0x8f420340, 0x156c001d, 0x0, 0x8f430074, 
-0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074, 
-0xafab004c, 0x26220001, 0x304203ff, 0xafa20054, 
-0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821, 
-0x8f420044, 0x8fac0064, 0x3c040001, 0x248439cc, 
-0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, 
-0x8f470070, 0x34a54500, 0x240b0001, 0xc002a03, 
-0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, 
-0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064, 
-0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff, 
-0xafa20054, 0x24020004, 0x1562000e, 0x111140, 
-0x111180, 0x24420cc0, 0x2e21021, 0xafa20044, 
-0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, 
-0x10400024, 0x25950020, 0x240c0001, 0x10000021, 
-0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, 
-0x8f420044, 0x8fab0064, 0x3c040001, 0x248439d8, 
-0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, 
-0x3c050007, 0xc002a03, 0x34a54800, 0x3c020008, 
-0x2c21024, 0x1440ff61, 0x0, 0x8f420360, 
-0x240c0001, 0xafac005c, 0x24420001, 0xaf420360, 
-0x1000ff90, 0x8f420360, 0x27a30036, 0x131040, 
-0x621821, 0x94620000, 0x441021, 0x1000001f, 
-0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084, 
-0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c, 
-0x25620020, 0xafa20028, 0x25620008, 0xafa20030, 
-0x25620010, 0xafab002c, 0xafa20034, 0x9562002a, 
-0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a, 
-0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018, 
-0x24630002, 0x822023, 0x1880ffdf, 0x26730001, 
-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc, 
-0x262102a, 0x14400030, 0x24030001, 0x8f83012c, 
-0x10600028, 0x0, 0x8f820124, 0x431023, 
-0x22143, 0x58800001, 0x24840040, 0x8f820128, 
-0x431023, 0x21943, 0x58600001, 0x24630040, 
-0x64102a, 0x54400001, 0x602021, 0xaf4400fc, 
-0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, 
-0x1000001a, 0x306200ff, 0x8fac008c, 0x101040, 
-0x4c1021, 0x94470018, 0x101080, 0x4c1021, 
-0xafbe0010, 0x8c420008, 0x3c040001, 0x248439f0, 
-0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, 
-0x2003021, 0xc002a03, 0xafa30014, 0x10000039, 
-0x0, 0x8f420324, 0x1821, 0x24420001, 
-0xaf420324, 0x8f420324, 0x306200ff, 0x1040ff06, 
-0x8021, 0x8f430008, 0x2402fbff, 0x1260002d, 
-0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c, 
-0x2669ffff, 0x2209021, 0x8e420008, 0x96270018, 
-0x8c440000, 0x8c450004, 0x56090004, 0x240b0001, 
-0x240c0002, 0x10000002, 0xafac0010, 0xafab0010, 
-0x16000004, 0xafa80014, 0x8f420008, 0x10000002, 
-0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021, 
-0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0, 
-0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2, 
-0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021, 
-0x5e102b, 0x10400003, 0x26310002, 0x8f42013c, 
-0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda, 
-0x26520004, 0x8fb00064, 0x1000001a, 0x0, 
-0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001, 
-0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c, 
-0x240c0002, 0xafac0010, 0x934305b5, 0xb1700, 
-0x10600003, 0x2223025, 0x3c020800, 0xc23025, 
-0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c, 
-0x3c03021, 0x40f809, 0x2003821, 0x1040fecb, 
-0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e, 
-0x934205b5, 0x14400004, 0x0, 0x97ab007e, 
-0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff, 
-0x1821024, 0x10400003, 0xc1402, 0x34630400, 
-0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006, 
-0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e, 
-0x1000000d, 0xa34005b5, 0x8fac0064, 0x3c02001f, 
-0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064, 
-0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05b5, 
-0x8f42013c, 0x3c2f023, 0x8fab0054, 0x8fac004c, 
-0xad8b0000, 0x8fac0064, 0x1580feba, 0x0, 
-0x8fab0064, 0x1160001b, 0x0, 0x934205b5, 
-0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0, 
-0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076, 
-0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, 
-0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008, 
-0xa44c000e, 0xac440000, 0xac450004, 0xac460008, 
-0x8f42033c, 0x24420001, 0xaf42033c, 0x10000010, 
-0x8f42033c, 0x8fab006c, 0x3164ffff, 0x2484fffc, 
-0x801821, 0x8f440240, 0x8f450244, 0x8f460118, 
-0x1021, 0xa32821, 0xa3382b, 0x822021, 
-0x872021, 0xaf440240, 0xc0f809, 0xaf450244, 
-0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, 
-0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008, 
-0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8, 
-0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048, 
-0x10620034, 0x0, 0x8f430048, 0x8f42004c, 
-0x622023, 0x4820001, 0x24840200, 0x8f430054, 
-0x8f42004c, 0x43102b, 0x14400004, 0x24020200, 
-0x8f43004c, 0x10000005, 0x431023, 0x8f420054, 
-0x8f43004c, 0x431023, 0x2442ffff, 0x405021, 
-0x8a102a, 0x54400001, 0x805021, 0x8f49004c, 
-0x8f48004c, 0x8f440178, 0x8f45017c, 0x8f46004c, 
-0x24071000, 0xafa70010, 0x84140, 0x1001821, 
-0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014, 
-0x1021, 0x63140, 0xafa70018, 0xa32821, 
-0xa3382b, 0x822021, 0x872021, 0x3402ecc0, 
-0xc23021, 0x8f420108, 0x2e63021, 0x40f809, 
-0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c, 
-0x8f420048, 0x14620018, 0x0, 0x8f420000, 
+0x882021, 0x40f809, 0x832021, 0x1040fe1f, 
+0x240a0001, 0xa34a05b5, 0x8fab006c, 0x8faa0064, 
+0x1705823, 0xafab006c, 0x8fab009c, 0x1505021, 
+0x16a102b, 0x10400004, 0xafaa0064, 0x8f42013c, 
+0x1425023, 0xafaa0064, 0x8f420358, 0x2442ffff, 
+0xaf420358, 0x8f420358, 0x8f42034c, 0x2442ffff, 
+0xaf42034c, 0x8fab0054, 0x8faa004c, 0x8f42034c, 
+0xad4b0000, 0x8f420044, 0x8f440088, 0x8f430078, 
+0x24420001, 0x441024, 0x24630001, 0xaf420044, 
+0xaf430078, 0x8faa006c, 0x1540fe1b, 0x0, 
+0x8fab006c, 0x1160001e, 0x0, 0x934205b5, 
+0x10400009, 0x0, 0x8faa0064, 0xaf4a00c4, 
+0xaf4b00c0, 0x8fab007c, 0xaf4b00c8, 0x8faa0074, 
+0x1000000e, 0xaf4a00cc, 0x97ab008e, 0x1160000b, 
+0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c, 
+0x97aa0086, 0x8c440004, 0x8c450008, 0xa44a000e, 
+0xac440000, 0xac450004, 0xac460008, 0x8f42033c, 
+0x24420001, 0xaf42033c, 0x10000010, 0x8f42033c, 
+0x8fab007c, 0x3164ffff, 0x2484fffc, 0x801821, 
+0x8f440240, 0x8f450244, 0x8f460118, 0x1021, 
+0xa32821, 0xa3382b, 0x822021, 0x872021, 
+0xaf440240, 0xc0f809, 0xaf450244, 0x8fbf00c8, 
+0x8fbe00c4, 0x8fb500c0, 0x8fb300bc, 0x8fb200b8, 
+0x8fb100b4, 0x8fb000b0, 0x3e00008, 0x27bd00d0, 
+0x3e00008, 0x0, 0x27bdff38, 0x240b0001, 
+0xafbf00c0, 0xafbe00bc, 0xafb500b8, 0xafb300b4, 
+0xafb200b0, 0xafb100ac, 0xafb000a8, 0xa3a00087, 
+0xafa00044, 0xafab005c, 0x934205b5, 0xa7a00076, 
+0x10400007, 0xa7a0007e, 0x8f4c00c0, 0xafac0064, 
+0x8f4b00c8, 0x8f5e00c4, 0x1000012d, 0xafab006c, 
+0x8f420114, 0x40f809, 0x0, 0x403021, 
+0x10c0029e, 0x0, 0x8cc20000, 0x8cc30004, 
+0xafa20020, 0xafa30024, 0x8fac0024, 0x8fbe0020, 
+0x3182ffff, 0x2442fffc, 0xafa20064, 0x3c020006, 
+0x2c21024, 0x14400015, 0xafac006c, 0x93c20000, 
+0x30420001, 0x10400011, 0x2402ffff, 0x8fc30000, 
+0x14620004, 0x3402ffff, 0x97c30004, 0x1062000b, 
+0x0, 0xc00233b, 0x3c02021, 0x304200ff, 
+0x14400006, 0x0, 0x8f420118, 0x40f809, 
+0x0, 0x1000027d, 0x0, 0x8fa20024, 
+0x3c03ffbf, 0x3463ffff, 0x431024, 0x3c03ffff, 
+0x431824, 0x14600003, 0xafa20024, 0x10000040, 
+0x8021, 0x3c020080, 0x621024, 0x10400007, 
+0x0, 0x8f42037c, 0x24420001, 0xaf42037c, 
+0x8f42037c, 0x10000036, 0x24100001, 0x8f420200, 
+0x24420001, 0xaf420200, 0x8f420200, 0x3c020001, 
+0x621024, 0x10400006, 0x3c020002, 0x8f4201b4, 
+0x24420001, 0xaf4201b4, 0x8f4201b4, 0x3c020002, 
+0x621024, 0x10400006, 0x3c020004, 0x8f42036c, 
+0x24420001, 0xaf42036c, 0x8f42036c, 0x3c020004, 
+0x621024, 0x10400006, 0x3c020008, 0x8f420370, 
+0x24420001, 0xaf420370, 0x8f420370, 0x3c020008, 
+0x621024, 0x10400006, 0x3c020010, 0x8f420374, 
+0x24420001, 0xaf420374, 0x8f420374, 0x3c020010, 
+0x621024, 0x10400006, 0x3c020020, 0x8f4201b0, 
+0x24420001, 0xaf4201b0, 0x8f4201b0, 0x3c020020, 
+0x621024, 0x10400006, 0x24100001, 0x8f420378, 
+0x24420001, 0xaf420378, 0x8f420378, 0x24100001, 
+0x8c020260, 0x8fab0064, 0x4b102b, 0x10400015, 
+0x320200ff, 0x8f4201d8, 0x24420001, 0xaf4201d8, 
+0x8f4201d8, 0x8fac006c, 0x8f8200e0, 0x358c0100, 
+0xafac006c, 0xafa20010, 0x8f8200e4, 0x24100001, 
+0x3c040001, 0x24843914, 0xafa20014, 0x8fa60020, 
+0x8fa70024, 0x3c050007, 0xc0029bb, 0x34a53600, 
+0x320200ff, 0x10400010, 0x3c020080, 0x2c21024, 
+0x1440000e, 0x32c20400, 0x8fab006c, 0x3c020080, 
+0x34420100, 0x1621024, 0x10400005, 0x0, 
+0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, 
+0x100001ff, 0x8fa30064, 0x32c20400, 0x10400012, 
+0x34028100, 0x97c3000c, 0x1462000f, 0x0, 
+0x240c0200, 0xa7ac0076, 0x97c2000e, 0x8fc30008, 
+0x8fc40004, 0x8fab0064, 0x8fc50000, 0x256bfffc, 
+0xafab0064, 0xa7a2007e, 0xafc3000c, 0xafc40008, 
+0xafc50004, 0x27de0004, 0x8fa70064, 0x320200ff, 
+0x14400031, 0x3c020100, 0x97c3000c, 0x2c6205dd, 
+0x10400015, 0x2821, 0x32c20800, 0x10400015, 
+0x24020800, 0x97c30014, 0x14620012, 0x3402aaaa, 
+0x97c3000e, 0x14620007, 0x2021, 0x97c30010, 
+0x24020300, 0x14620004, 0x801021, 0x97c20012, 
+0x2c440001, 0x801021, 0x54400006, 0x24050016, 
+0x10000004, 0x0, 0x24020800, 0x50620001, 
+0x2405000e, 0x10a00013, 0x3c52021, 0x24830009, 
+0x3c02001f, 0x3442ffff, 0x43102b, 0x10400003, 
+0x0, 0x8f42013c, 0x621823, 0x90620000, 
+0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 
+0x621825, 0x10600004, 0x3c020100, 0x94820002, 
+0x453821, 0x3c020100, 0x2c21024, 0x5040000e, 
+0xafa70064, 0x8fac0064, 0x10ec0008, 0x3c050007, 
+0x3c040001, 0x2484397c, 0x8fa60064, 0x34a54000, 
+0xafa00010, 0xc0029bb, 0xafa00014, 0x8fab0064, 
+0x256b0004, 0xafab0064, 0x8f420080, 0x8fac0064, 
+0x4c102b, 0x1040002c, 0x32c28000, 0x10400034, 
+0x240b0003, 0x32c21000, 0x10400031, 0xafab005c, 
+0x1000002e, 0x240c0004, 0x8f420340, 0x2403ffbf, 
+0x283a024, 0x24420001, 0xaf420340, 0x10000173, 
+0x8f420340, 0x3c020800, 0x2c2b025, 0x2402ffbf, 
+0x282a024, 0x8f830128, 0x3c040001, 0x24843944, 
+0x26620001, 0xafa20014, 0xafa30010, 0x8f860120, 
+0x8f870124, 0x3c050007, 0xc0029bb, 0x34a55300, 
+0x10000162, 0x0, 0x8ea20000, 0x8ea30004, 
+0x3c040001, 0x2484395c, 0xafb00010, 0xafb10014, 
+0x8ea70018, 0x34a55900, 0xc0029bb, 0x603021, 
+0x10000156, 0x0, 0x8f420084, 0x8fab0064, 
+0x4b102b, 0x14400007, 0x3c020001, 0x2c21024, 
+0x10400004, 0x0, 0x240c0002, 0xafac005c, 
+0x8fab0064, 0x11600166, 0x27ac0020, 0xafac008c, 
+0x8fab005c, 0x240c0001, 0x556c0021, 0x240c0002, 
+0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054, 
+0x8f510054, 0x3403ecc0, 0xafab004c, 0x26220001, 
+0x304201ff, 0xafa20054, 0x111140, 0x431021, 
+0x1000006b, 0x2e2a821, 0x8f420044, 0x8fac0064, 
+0x3c040001, 0x24843920, 0xafac0014, 0xafa20010, 
+0x8f460054, 0x8f470050, 0x3c050007, 0xc0029bb, 
+0x34a54300, 0x8f430340, 0x2402ffbf, 0x282a024, 
+0x24630001, 0xaf430340, 0x10000124, 0x8f420340, 
+0x156c001d, 0x0, 0x8f430074, 0x8f420070, 
+0x1062000a, 0x274b0074, 0x8f510074, 0xafab004c, 
+0x26220001, 0x304203ff, 0xafa20054, 0x111140, 
+0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044, 
+0x8fac0064, 0x3c040001, 0x2484392c, 0x3c050007, 
+0xafac0014, 0xafa20010, 0x8f460074, 0x8f470070, 
+0x34a54500, 0x240b0001, 0xc0029bb, 0xafab005c, 
+0x1000ffc3, 0x0, 0x8f430064, 0x8f420060, 
+0x1062001a, 0x274c0064, 0x8f510064, 0x8fab005c, 
+0xafac004c, 0x26220001, 0x304200ff, 0xafa20054, 
+0x24020004, 0x1562000e, 0x111140, 0x111180, 
+0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a, 
+0x8fac0044, 0x8fab0064, 0x4b102b, 0x10400024, 
+0x25950020, 0x240c0001, 0x10000021, 0xa3ac0087, 
+0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, 
+0x8fab0064, 0x3c040001, 0x24843938, 0xafab0014, 
+0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007, 
+0xc0029bb, 0x34a54800, 0x3c020008, 0x2c21024, 
+0x1440ff61, 0x0, 0x8f420360, 0x240c0001, 
+0xafac005c, 0x24420001, 0xaf420360, 0x1000ff90, 
+0x8f420360, 0x27a30036, 0x131040, 0x621821, 
+0x94620000, 0x441021, 0x1000001f, 0xa4620000, 
+0xaebe0018, 0x93a20087, 0x10400084, 0x9821, 
+0x8fab0044, 0x8fa40064, 0x8fa3008c, 0x25620020, 
+0xafa20028, 0x25620008, 0xafa20030, 0x25620010, 
+0xafab002c, 0xafa20034, 0x9562002a, 0xa7a20038, 
+0x95620018, 0xa7a2003a, 0x9562001a, 0xa7a2003c, 
+0x9562001c, 0xa7a2003e, 0x94620018, 0x24630002, 
+0x822023, 0x1880ffdf, 0x26730001, 0x2e620004, 
+0x1440fff9, 0x0, 0x8f4200fc, 0x262102a, 
+0x14400030, 0x24030001, 0x8f83012c, 0x10600028, 
+0x0, 0x8f820124, 0x431023, 0x22143, 
+0x58800001, 0x24840040, 0x8f820128, 0x431023, 
+0x21943, 0x58600001, 0x24630040, 0x64102a, 
+0x54400001, 0x602021, 0xaf4400fc, 0x8f4200fc, 
+0x262102a, 0x10400016, 0x24030001, 0x1000001a, 
+0x306200ff, 0x8fac008c, 0x101040, 0x4c1021, 
+0x94470018, 0x101080, 0x4c1021, 0xafbe0010, 
+0x8c420008, 0x3c040001, 0x24843950, 0x3c050007, 
+0x8c430004, 0x8c420000, 0x34a55500, 0x2003021, 
+0xc0029bb, 0xafa30014, 0x10000039, 0x0, 
+0x8f420324, 0x1821, 0x24420001, 0xaf420324, 
+0x8f420324, 0x306200ff, 0x1040ff06, 0x8021, 
+0x8f430008, 0x2402fbff, 0x1260002d, 0x625024, 
+0x3c0b4000, 0x22b4025, 0x8fb1008c, 0x2669ffff, 
+0x2209021, 0x8e420008, 0x96270018, 0x8c440000, 
+0x8c450004, 0x56090004, 0x240b0001, 0x240c0002, 
+0x10000002, 0xafac0010, 0xafab0010, 0x16000004, 
+0xafa80014, 0x8f420008, 0x10000002, 0xafa20018, 
+0xafaa0018, 0x8f42010c, 0x3c03021, 0xafa80098, 
+0xafa9009c, 0x40f809, 0xafaa00a0, 0x8fa80098, 
+0x8fa9009c, 0x8faa00a0, 0x1040ffc2, 0x3c02001f, 
+0x96230018, 0x3442ffff, 0x3c3f021, 0x5e102b, 
+0x10400003, 0x26310002, 0x8f42013c, 0x3c2f023, 
+0x26100001, 0x213102b, 0x1440ffda, 0x26520004, 
+0x8fb00064, 0x1000001a, 0x0, 0x96a3000a, 
+0x8fb00064, 0x70102b, 0x54400001, 0x608021, 
+0x8ea40000, 0x8ea50004, 0x8fab005c, 0x240c0002, 
+0xafac0010, 0x934305b5, 0xb1700, 0x10600003, 
+0x2223025, 0x3c020800, 0xc23025, 0xafa60014, 
+0x8f420008, 0xafa20018, 0x8f42010c, 0x3c03021, 
+0x40f809, 0x2003821, 0x1040fecb, 0x3c050007, 
+0x97ac0076, 0x11800007, 0x96a3000e, 0x934205b5, 
+0x14400004, 0x0, 0x97ab007e, 0x6c1825, 
+0xa6ab0016, 0x8fac006c, 0x3c02ffff, 0x1821024, 
+0x10400003, 0xc1402, 0x34630400, 0xa6a20014, 
+0xa6b0000a, 0x8fab0064, 0x560b0006, 0x3d0f021, 
+0x34620004, 0xafa00064, 0xa6a2000e, 0x1000000d, 
+0xa34005b5, 0x8fac0064, 0x3c02001f, 0x3442ffff, 
+0x5e102b, 0x1906023, 0xafac0064, 0xa6a3000e, 
+0x240b0001, 0x10400003, 0xa34b05b5, 0x8f42013c, 
+0x3c2f023, 0x8fab0054, 0x8fac004c, 0xad8b0000, 
+0x8fac0064, 0x1580feba, 0x0, 0x8fab0064, 
+0x1160001b, 0x0, 0x934205b5, 0x10400006, 
+0x0, 0xaf5e00c4, 0xaf4b00c0, 0x8fac006c, 
+0x1000000e, 0xaf4c00c8, 0x97ab0076, 0x1160000b, 
+0x34038100, 0x8fa20020, 0x8c46000c, 0xa443000c, 
+0x97ac007e, 0x8c440004, 0x8c450008, 0xa44c000e, 
+0xac440000, 0xac450004, 0xac460008, 0x8f42033c, 
+0x24420001, 0xaf42033c, 0x10000010, 0x8f42033c, 
+0x8fab006c, 0x3164ffff, 0x2484fffc, 0x801821, 
+0x8f440240, 0x8f450244, 0x8f460118, 0x1021, 
+0xa32821, 0xa3382b, 0x822021, 0x872021, 
+0xaf440240, 0xc0f809, 0xaf450244, 0x8fbf00c0, 
+0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, 0x8fb200b0, 
+0x8fb100ac, 0x8fb000a8, 0x3e00008, 0x27bd00c8, 
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, 
+0xafb00020, 0x8f43005c, 0x8f420058, 0x10620049, 
+0x0, 0x8f430058, 0x8f42005c, 0x622023, 
+0x4820001, 0x24840100, 0x8f430064, 0x8f42005c, 
+0x43102b, 0x14400004, 0x24020100, 0x8f43005c, 
+0x10000005, 0x431023, 0x8f420064, 0x8f43005c, 
+0x431023, 0x2442ffff, 0x403821, 0x87102a, 
+0x54400001, 0x803821, 0x8f42005c, 0x471021, 
+0x305000ff, 0x32c21000, 0x10400015, 0x24082000, 
+0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, 
+0x73980, 0xafa80010, 0xafb00014, 0x8f480014, 
+0x94980, 0x1201821, 0x1021, 0xa32821, 
+0xa3482b, 0x822021, 0x892021, 0x63180, 
+0xafa80018, 0x8f420108, 0x10000014, 0x24c60cc0, 
+0x8f49005c, 0x8f440180, 0x8f450184, 0x8f46005c, 
+0x73940, 0xafa80010, 0xafb00014, 0x8f480014, 
+0x94940, 0x1201821, 0x1021, 0xa32821, 
+0xa3482b, 0x822021, 0x892021, 0x63140, 
+0xafa80018, 0x8f420108, 0x24c64cc0, 0x40f809, 
+0x2e63021, 0x54400001, 0xaf50005c, 0x8f43005c, 
+0x8f420058, 0x14620018, 0x0, 0x8f420000, 
 0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 
 0x1040fffd, 0x0, 0x10000005, 0x0, 
 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 
-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, 
+0x8f820060, 0x2403feff, 0x431024, 0xaf820060, 
 0x8f420000, 0x10400003, 0x0, 0x10000002, 
 0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, 
 0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 
-0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c, 
-0x8f420058, 0x10620049, 0x0, 0x8f430058, 
-0x8f42005c, 0x622023, 0x4820001, 0x24840100, 
-0x8f430064, 0x8f42005c, 0x43102b, 0x14400004, 
-0x24020100, 0x8f43005c, 0x10000005, 0x431023, 
-0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff, 
-0x403821, 0x87102a, 0x54400001, 0x803821, 
-0x8f42005c, 0x471021, 0x305000ff, 0x32c21000, 
-0x10400015, 0x24082000, 0x8f49005c, 0x8f440180, 
-0x8f450184, 0x8f46005c, 0x73980, 0xafa80010, 
-0xafb00014, 0x8f480014, 0x94980, 0x1201821, 
-0x1021, 0xa32821, 0xa3482b, 0x822021, 
-0x892021, 0x63180, 0xafa80018, 0x8f420108, 
-0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440180, 
-0x8f450184, 0x8f46005c, 0x73940, 0xafa80010, 
-0xafb00014, 0x8f480014, 0x94940, 0x1201821, 
-0x1021, 0xa32821, 0xa3482b, 0x822021, 
-0x892021, 0x63140, 0xafa80018, 0x8f420108, 
-0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001, 
-0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018, 
-0x0, 0x8f420000, 0x10400007, 0x0, 
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 
-0x10000005, 0x0, 0xaf800048, 0x8f820048, 
-0x1040fffd, 0x0, 0x8f820060, 0x2403feff, 
-0x431024, 0xaf820060, 0x8f420000, 0x10400003, 
-0x0, 0x10000002, 0xaf80004c, 0xaf800048, 
-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, 
-0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033, 
-0x0, 0x8f430068, 0x8f42006c, 0x622023, 
-0x4820001, 0x24840400, 0x8f430074, 0x8f42006c, 
-0x43102b, 0x14400004, 0x24020400, 0x8f43006c, 
-0x10000005, 0x431023, 0x8f420074, 0x8f43006c, 
-0x431023, 0x2442ffff, 0x405021, 0x8a102a, 
-0x54400001, 0x805021, 0x8f49006c, 0x8f48006c, 
-0x8f440188, 0x8f45018c, 0x8f46006c, 0x24074000, 
-0xafa70010, 0x84140, 0x1001821, 0x12a4821, 
-0x313003ff, 0xafb00014, 0x8f470014, 0x1021, 
-0x63140, 0x24c66cc0, 0xafa70018, 0xa32821, 
-0xa3382b, 0x822021, 0x872021, 0x8f420108, 
-0x2e63021, 0x40f809, 0xa3940, 0x54400001, 
-0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018, 
-0x0, 0x8f420000, 0x10400007, 0x0, 
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 
-0x10000005, 0x0, 0xaf800048, 0x8f820048, 
-0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff, 
-0x431024, 0xaf820060, 0x8f420000, 0x10400003, 
-0x0, 0x10000002, 0xaf80004c, 0xaf800048, 
-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, 
-0x3e00008, 0x0, 0x8f4200fc, 0x3c030001, 
-0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc, 
-0x8f850128, 0x2e31021, 0x54820004, 0x24820008, 
-0x3c020001, 0x34422ec8, 0x2e21021, 0x401821, 
-0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004, 
-0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128, 
-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, 
-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, 
-0x401821, 0x8c620004, 0x21140, 0xa21021, 
-0xaf820128, 0xac600000, 0x8ca30018, 0x30620070, 
-0x1040002d, 0x30620020, 0x10400004, 0x3c020010, 
-0x2c21024, 0x1040000d, 0x0, 0x30620040, 
-0x10400004, 0x3c020020, 0x2c21024, 0x10400007, 
-0x0, 0x30620010, 0x1040001f, 0x3c020040, 
-0x2c21024, 0x1440001c, 0x0, 0x8f820040, 
-0x30420001, 0x14400008, 0x2021, 0x8c030104, 
-0x24020001, 0x50620005, 0x24040001, 0x8c020264, 
-0x10400003, 0x801021, 0x24040001, 0x801021, 
-0x10400006, 0x0, 0x8f4202fc, 0x24420001, 
-0xaf4202fc, 0x10000008, 0x8f4202fc, 0x8f820044, 
-0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, 
-0xaf4202f8, 0x8f4202f8, 0x3e00008, 0x0, 
-0x3e00008, 0x0, 0x27bdffa0, 0xafbf0058, 
-0xafbe0054, 0xafb50050, 0xafb3004c, 0xafb20048, 
-0xafb10044, 0xafb00040, 0x8f4200fc, 0x24420001, 
-0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128, 
-0x8d030018, 0x30620070, 0x1040002e, 0x30620020, 
+0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43006c, 
+0x8f420068, 0x10620033, 0x0, 0x8f430068, 
+0x8f42006c, 0x622023, 0x4820001, 0x24840400, 
+0x8f430074, 0x8f42006c, 0x43102b, 0x14400004, 
+0x24020400, 0x8f43006c, 0x10000005, 0x431023, 
+0x8f420074, 0x8f43006c, 0x431023, 0x2442ffff, 
+0x405021, 0x8a102a, 0x54400001, 0x805021, 
+0x8f49006c, 0x8f48006c, 0x8f440188, 0x8f45018c, 
+0x8f46006c, 0x24074000, 0xafa70010, 0x84140, 
+0x1001821, 0x12a4821, 0x313003ff, 0xafb00014, 
+0x8f470014, 0x1021, 0x63140, 0x24c66cc0, 
+0xafa70018, 0xa32821, 0xa3382b, 0x822021, 
+0x872021, 0x8f420108, 0x2e63021, 0x40f809, 
+0xa3940, 0x54400001, 0xaf50006c, 0x8f43006c, 
+0x8f420068, 0x14620018, 0x0, 0x8f420000, 
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c, 
+0x1040fffd, 0x0, 0x10000005, 0x0, 
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 
+0x8f820060, 0x2403f7ff, 0x431024, 0xaf820060, 
+0x8f420000, 0x10400003, 0x0, 0x10000002, 
+0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, 
+0x3e00008, 0x27bd0028, 0x3e00008, 0x0, 
+0x8f4200fc, 0x3c030001, 0x8f4400f8, 0x346330c8, 
+0x24420001, 0xaf4200fc, 0x8f850128, 0x2e31021, 
+0x54820004, 0x24820008, 0x3c020001, 0x34422ec8, 
+0x2e21021, 0x401821, 0xaf4300f8, 0xac600000, 
+0x8f4200f4, 0x14620004, 0x3c020001, 0x24a20020, 
+0x1000000f, 0xaf820128, 0x8f4300f8, 0x344230c8, 
+0x2e21021, 0x54620004, 0x24620008, 0x3c020001, 
+0x34422ec8, 0x2e21021, 0x401821, 0x8c620004, 
+0x21140, 0xa21021, 0xaf820128, 0xac600000, 
+0x8ca30018, 0x30620070, 0x1040002d, 0x30620020, 
 0x10400004, 0x3c020010, 0x2c21024, 0x1040000d, 
 0x0, 0x30620040, 0x10400004, 0x3c020020, 
 0x2c21024, 0x10400007, 0x0, 0x30620010, 
-0x10400193, 0x3c020040, 0x2c21024, 0x14400190, 
+0x1040001f, 0x3c020040, 0x2c21024, 0x1440001c, 
 0x0, 0x8f820040, 0x30420001, 0x14400008, 
 0x2021, 0x8c030104, 0x24020001, 0x50620005, 
 0x24040001, 0x8c020264, 0x10400003, 0x801021, 
 0x24040001, 0x801021, 0x10400006, 0x0, 
-0x8f4202fc, 0x24420001, 0xaf4202fc, 0x1000017c, 
+0x8f4202fc, 0x24420001, 0xaf4202fc, 0x10000008, 
 0x8f4202fc, 0x8f820044, 0x34420004, 0xaf820044, 
-0x8f4202f8, 0x24420001, 0xaf4202f8, 0x10000174, 
-0x8f4202f8, 0x30620002, 0x10400135, 0x3c020800, 
-0x8d0a001c, 0x1422024, 0xafaa0024, 0xa5702, 
-0xafaa0034, 0x8faa0024, 0x314affff, 0xafaa0024, 
-0x950a0016, 0xafaa002c, 0x8faa0034, 0x24020001, 
-0x15420007, 0x24020002, 0x8faa0024, 0xa1140, 
-0x3403ecc0, 0x431021, 0x10000014, 0x2e2a821, 
-0x15420006, 0x24020003, 0x8faa0024, 0xa1140, 
-0x24426cc0, 0x1000000d, 0x2e2a821, 0x8faa0034, 
-0x15420006, 0x0, 0x8faa0024, 0xa1140, 
-0x24424cc0, 0x10000005, 0x2e2a821, 0x8faa0024, 
-0xa1180, 0x571021, 0x24550ce0, 0x96a2000e, 
-0x305efffc, 0x30420400, 0x144000c5, 0x8821, 
-0x10800004, 0x24091000, 0x97b1002e, 0x100000c1, 
-0x0, 0x8eb30018, 0x9663000c, 0x2c6205dd, 
+0x8f4202f8, 0x24420001, 0xaf4202f8, 0x8f4202f8, 
+0x3e00008, 0x0, 0x3e00008, 0x0, 
+0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb50058, 
+0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048, 
+0x8f4200fc, 0x24420001, 0xaf4200fc, 0x8f880128, 
+0x25020020, 0xaf820128, 0x8d030018, 0x30620070, 
+0x1040002e, 0x30620020, 0x10400004, 0x3c020010, 
+0x2c21024, 0x1040000d, 0x0, 0x30620040, 
+0x10400004, 0x3c020020, 0x2c21024, 0x10400007, 
+0x0, 0x30620010, 0x104001a6, 0x3c020040, 
+0x2c21024, 0x144001a3, 0x0, 0x8f820040, 
+0x30420001, 0x14400008, 0x2021, 0x8c030104, 
+0x24020001, 0x50620005, 0x24040001, 0x8c020264, 
+0x10400003, 0x801021, 0x24040001, 0x801021, 
+0x10400006, 0x0, 0x8f4202fc, 0x24420001, 
+0xaf4202fc, 0x1000018f, 0x8f4202fc, 0x8f820044, 
+0x34420004, 0xaf820044, 0x8f4202f8, 0x24420001, 
+0xaf4202f8, 0x10000187, 0x8f4202f8, 0x30620002, 
+0x10400148, 0x3c020800, 0x8d0a001c, 0x1422024, 
+0xafaa0024, 0xa5702, 0xafaa0034, 0x8faa0024, 
+0x314affff, 0xafaa0024, 0x950a0016, 0xafaa002c, 
+0x8faa0034, 0x24020001, 0x15420007, 0x24020002, 
+0x8faa0024, 0xa1140, 0x3403ecc0, 0x431021, 
+0x10000014, 0x2e2a821, 0x15420006, 0x24020003, 
+0x8faa0024, 0xa1140, 0x24426cc0, 0x1000000d, 
+0x2e2a821, 0x8faa0034, 0x15420006, 0x0, 
+0x8faa0024, 0xa1140, 0x24424cc0, 0x10000005, 
+0x2e2a821, 0x8faa0024, 0xa1180, 0x571021, 
+0x24550ce0, 0x96a2000e, 0x305efffc, 0x30420400, 
+0x144000d8, 0x8821, 0x10800004, 0x24091000, 
+0x97b1002e, 0x100000d4, 0x0, 0x8eb30018, 
+0x966a000c, 0xa7aa003e, 0x97a3003e, 0x2c6205dd, 
 0x10400015, 0x2021, 0x32c20800, 0x10400015, 
 0x24020800, 0x96630014, 0x14620012, 0x3402aaaa, 
 0x9663000e, 0x14620007, 0x2821, 0x96630010, 
 0x24020300, 0x14620004, 0xa01021, 0x96620012, 
 0x2c450001, 0xa01021, 0x54400006, 0x24040016, 
 0x10000004, 0x0, 0x24020800, 0x50620001, 
-0x2404000e, 0x108000a2, 0x2649021, 0x92420000, 
+0x2404000e, 0x108000b3, 0x2649021, 0x92420000, 
 0x3042000f, 0x28080, 0x32c20100, 0x1040001e, 
 0x2501821, 0x3c020020, 0x43102b, 0x1440000e, 
 0x2402021, 0x2821, 0x94820000, 0x24840002, 
 0xa22821, 0x83102b, 0x1440fffb, 0x30a2ffff, 
 0x51c02, 0x622821, 0x51c02, 0x30a2ffff, 
 0x10000009, 0x622821, 0x8f47013c, 0x8f420110, 
-0x102842, 0x3c060020, 0x40f809, 0xafa80038, 
-0x3045ffff, 0x8fa80038, 0x50a00001, 0x3405ffff, 
+0x102842, 0x3c060020, 0x40f809, 0xafa80040, 
+0x3045ffff, 0x8fa80040, 0x50a00001, 0x3405ffff, 
 0x10000002, 0x37de0002, 0x2821, 0x32c20080, 
-0x1040007b, 0xa6a50010, 0x26430009, 0x3c02001f, 
+0x1040008c, 0xa6a50010, 0x26430009, 0x3c02001f, 
 0x3442ffff, 0x43102b, 0x10400003, 0x0, 
 0x8f42013c, 0x621823, 0x90660000, 0x30c200ff, 
 0x38430006, 0x2c630001, 0x38420011, 0x2c420001, 
-0x621825, 0x1060006b, 0x24091000, 0x8821, 
-0x2602021, 0x94820000, 0x24840002, 0x2228821, 
-0x92102b, 0x1440fffb, 0x111c02, 0x3222ffff, 
-0x628821, 0x111c02, 0x3222ffff, 0x628821, 
-0x32c20200, 0x10400003, 0x26440006, 0x1000003e, 
-0x8021, 0x3c05001f, 0x34a5ffff, 0xa4102b, 
-0x10400003, 0x0, 0x8f42013c, 0x822023, 
-0x94820000, 0x30421fff, 0x10400004, 0x2644000c, 
-0x96420002, 0x10000030, 0x508023, 0x96420002, 
-0x26430014, 0x508023, 0x3c020020, 0x43102b, 
-0x1440000a, 0xd08021, 0x9642000c, 0x2028021, 
-0x9642000e, 0x96430010, 0x96440012, 0x2028021, 
-0x2038021, 0x10000020, 0x2048021, 0xa4102b, 
-0x10400003, 0x0, 0x8f42013c, 0x822023, 
-0x94820000, 0x24840002, 0x2028021, 0xa4102b, 
-0x10400003, 0x0, 0x8f42013c, 0x822023, 
-0x94820000, 0x24840002, 0x2028021, 0xa4102b, 
-0x10400003, 0x0, 0x8f42013c, 0x822023, 
-0x94820000, 0x24840002, 0x2028021, 0xa4102b, 
-0x10400003, 0x0, 0x8f42013c, 0x822023, 
-0x94820000, 0x2028021, 0x3c020100, 0x2c21024, 
-0x1040000c, 0x33c20004, 0x1040000a, 0x0, 
-0x9504000e, 0x2642021, 0xc003cf8, 0x2484fffc, 
-0x3042ffff, 0x2228821, 0x111c02, 0x3222ffff, 
-0x628821, 0x8faa002c, 0x1518823, 0x111402, 
-0x2228821, 0x2308821, 0x111402, 0x2228821, 
-0x3231ffff, 0x52200001, 0x3411ffff, 0x37de0001, 
-0x24091000, 0x33c20004, 0xa6b10012, 0x10400002, 
-0xa6be000e, 0x34098000, 0x8f480044, 0x8f440190, 
-0x8f450194, 0xafa90010, 0x8f490044, 0x84140, 
-0x1001821, 0xafa90014, 0x8f48000c, 0x2a03021, 
-0x24070020, 0xafa80018, 0x8f48010c, 0x1021, 
-0xa32821, 0xa3482b, 0x822021, 0x100f809, 
-0x892021, 0x1440000c, 0x0, 0x8f820128, 
-0x8faa0024, 0x3c040001, 0x24843a28, 0xafaa0014, 
-0xafa20010, 0x8f860124, 0x8f870120, 0x3c050007, 
-0xc002a03, 0x34a59920, 0x8f420358, 0x2442ffff, 
-0xaf420358, 0x8f420044, 0x8f430088, 0x24420001, 
-0x431024, 0xaf420044, 0x8faa0034, 0x8f440358, 
-0x24020001, 0x15420006, 0x24020002, 0x8f42034c, 
-0x2442ffff, 0xaf42034c, 0x10000049, 0x8f42034c, 
-0x15420006, 0x0, 0x8f420354, 0x2442ffff, 
-0xaf420354, 0x10000042, 0x8f420354, 0x8f420350, 
-0x2442ffff, 0xaf420350, 0x1000003d, 0x8f420350, 
-0x30621000, 0x10400005, 0x30628000, 0x8f420078, 
-0x24420001, 0x10000036, 0xaf420078, 0x10400034, 
-0x0, 0x8f420078, 0x24420001, 0xaf420078, 
-0x8c030240, 0x43102b, 0x1440002d, 0x24070008, 
-0x8f440158, 0x8f45015c, 0x8f430044, 0x8f48000c, 
-0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, 
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
-0x14400011, 0x24020001, 0x3c010001, 0x370821, 
-0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, 
-0x3c040001, 0x248439ac, 0xafa20014, 0x8f460044, 
-0x8f870120, 0x3c050009, 0xc002a03, 0x34a51300, 
-0x1000000b, 0x0, 0x8f4202f4, 0x24420001, 
-0xaf4202f4, 0x8f4202f4, 0x8f420044, 0xaf42007c, 
-0x3c010001, 0x370821, 0xa02040f2, 0xaf400078, 
-0x8f420308, 0x24420001, 0xaf420308, 0x8f420308, 
-0x8fbf0058, 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 
-0x8fb20048, 0x8fb10044, 0x8fb00040, 0x3e00008, 
-0x27bd0060, 0x3e00008, 0x0, 0x8f420130, 
+0x621825, 0x1060007b, 0x24020800, 0x8821, 
+0x97a3003e, 0x1462000f, 0x2602021, 0x96710000, 
+0x96620002, 0x96630004, 0x96640006, 0x2228821, 
+0x2238821, 0x2248821, 0x96620008, 0x9663000a, 
+0x9664000c, 0x2228821, 0x2238821, 0x10000007, 
+0x2248821, 0x94820000, 0x24840002, 0x2228821, 
+0x92102b, 0x1440fffb, 0x0, 0x111c02, 
+0x3222ffff, 0x628821, 0x111c02, 0x3222ffff, 
+0x628821, 0x32c20200, 0x10400003, 0x26440006, 
+0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff, 
+0xa4102b, 0x10400003, 0x0, 0x8f42013c, 
+0x822023, 0x94820000, 0x30421fff, 0x10400004, 
+0x2644000c, 0x96420002, 0x10000030, 0x508023, 
+0x96420002, 0x26430014, 0x508023, 0x3c020020, 
+0x43102b, 0x1440000a, 0xd08021, 0x9642000c, 
+0x2028021, 0x9642000e, 0x96430010, 0x96440012, 
+0x2028021, 0x2038021, 0x10000020, 0x2048021, 
+0xa4102b, 0x10400003, 0x0, 0x8f42013c, 
+0x822023, 0x94820000, 0x24840002, 0x2028021, 
+0xa4102b, 0x10400003, 0x0, 0x8f42013c, 
+0x822023, 0x94820000, 0x24840002, 0x2028021, 
+0xa4102b, 0x10400003, 0x0, 0x8f42013c, 
+0x822023, 0x94820000, 0x24840002, 0x2028021, 
+0xa4102b, 0x10400003, 0x0, 0x8f42013c, 
+0x822023, 0x94820000, 0x2028021, 0x3c020100, 
+0x2c21024, 0x1040000c, 0x33c20004, 0x1040000a, 
+0x0, 0x9504000e, 0x2642021, 0xc003c24, 
+0x2484fffc, 0x3042ffff, 0x2228821, 0x111c02, 
+0x3222ffff, 0x628821, 0x8faa002c, 0x1518823, 
+0x111402, 0x2228821, 0x2308821, 0x111402, 
+0x2228821, 0x3231ffff, 0x52200001, 0x3411ffff, 
+0x37de0001, 0x24091000, 0x33c20004, 0xa6b10012, 
+0x10400002, 0xa6be000e, 0x34098000, 0x8f480044, 
+0x8f440190, 0x8f450194, 0xafa90010, 0x8f490044, 
+0x84140, 0x1001821, 0xafa90014, 0x8f48000c, 
+0x2a03021, 0x24070020, 0xafa80018, 0x8f48010c, 
+0x1021, 0xa32821, 0xa3482b, 0x822021, 
+0x100f809, 0x892021, 0x1440000c, 0x0, 
+0x8f820128, 0x8faa0024, 0x3c040001, 0x24843988, 
+0xafaa0014, 0xafa20010, 0x8f860124, 0x8f870120, 
+0x3c050007, 0xc0029bb, 0x34a59920, 0x8f420358, 
+0x2442ffff, 0xaf420358, 0x8f420044, 0x8f430088, 
+0x24420001, 0x431024, 0xaf420044, 0x8faa0034, 
+0x8f440358, 0x24020001, 0x15420006, 0x24020002, 
+0x8f42034c, 0x2442ffff, 0xaf42034c, 0x10000049, 
+0x8f42034c, 0x15420006, 0x0, 0x8f420354, 
+0x2442ffff, 0xaf420354, 0x10000042, 0x8f420354, 
+0x8f420350, 0x2442ffff, 0xaf420350, 0x1000003d, 
+0x8f420350, 0x30621000, 0x10400005, 0x30628000, 
+0x8f420078, 0x24420001, 0x10000036, 0xaf420078, 
+0x10400034, 0x0, 0x8f420078, 0x24420001, 
+0xaf420078, 0x8c030240, 0x43102b, 0x1440002d, 
+0x24070008, 0x8f440158, 0x8f45015c, 0x8f430044, 
+0x8f48000c, 0x8f860120, 0x24020040, 0xafa20010, 
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
+0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
+0x370821, 0xa02240f2, 0x8f820124, 0xafa20010, 
+0x8f820128, 0x3c040001, 0x2484390c, 0xafa20014, 
+0x8f460044, 0x8f870120, 0x3c050009, 0xc0029bb, 
+0x34a51300, 0x1000000b, 0x0, 0x8f4202f4, 
+0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8f420044, 
+0xaf42007c, 0x3c010001, 0x370821, 0xa02040f2, 
+0xaf400078, 0x8f420308, 0x24420001, 0xaf420308, 
+0x8f420308, 0x8fbf0060, 0x8fbe005c, 0x8fb50058, 
+0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048, 
+0x3e00008, 0x27bd0068, 0x3e00008, 0x0, 
+0x0, 0x0, 0x0, 0x8f420130, 
 0xaf8200c0, 0x8f420130, 0xaf8200c4, 0x8f420130, 
 0xaf8200c8, 0x8f42012c, 0xaf8200d0, 0x8f42012c, 
 0xaf8200d4, 0x8f42012c, 0x3e00008, 0xaf8200d8, 
 0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, 
-0xc002a87, 0x24060008, 0x8c020204, 0xc003e1e, 
+0xc002a3f, 0x24060008, 0x8c020204, 0xc003d4a, 
 0xaf820210, 0x2021, 0x8c060248, 0x24020004, 
-0x3c010001, 0xac223e28, 0xc0048a8, 0x24050004, 
-0x3c020001, 0x8c423e24, 0x30420001, 0x10400007, 
-0x24020001, 0x3c010001, 0xac223e28, 0x2021, 
-0x24050001, 0xc0048a8, 0x3c06601b, 0x3c040001, 
-0x24843af0, 0x8f420144, 0x8f430148, 0x3c050008, 
+0x3c010001, 0xac223d88, 0xc0047d4, 0x24050004, 
+0x3c020001, 0x8c423d84, 0x30420001, 0x10400007, 
+0x24020001, 0x3c010001, 0xac223d88, 0x2021, 
+0x24050001, 0xc0047d4, 0x3c06601b, 0x3c040001, 
+0x24843a50, 0x8f420144, 0x8f430148, 0x3c050008, 
 0x8f46014c, 0x21640, 0x31940, 0x34630403, 
 0x431025, 0x633c0, 0x461025, 0xaf82021c, 
 0xafa00010, 0xafa00014, 0x8f86021c, 0x34a50200, 
-0xc002a03, 0x3821, 0x3c010001, 0xac203e20, 
-0x3c010001, 0xac203e38, 0x8fbf0018, 0x3e00008, 
+0xc0029bb, 0x3821, 0x3c010001, 0xac203d80, 
+0x3c010001, 0xac203d98, 0x8fbf0018, 0x3e00008, 
 0x27bd0020, 0x27bdffe0, 0x3c050008, 0x34a50300, 
 0xafbf0018, 0xafa00010, 0xafa00014, 0x8f860200, 
-0x3c040001, 0x24843afc, 0xc002a03, 0x3821, 
+0x3c040001, 0x24843a5c, 0xc0029bb, 0x3821, 
 0x8f420400, 0x24420001, 0xaf420400, 0x8f420400, 
 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffd8, 
 0xafbf0020, 0xafb1001c, 0xafb00018, 0x8f420394, 
 0x24420001, 0xaf420394, 0x8f420394, 0x8f900220, 
-0x8f4303a8, 0x3c020001, 0x8c423e38, 0x3c040001, 
-0x24843b08, 0x3c050008, 0xafa20014, 0xafa30010, 
-0x8f4703ac, 0x34a50400, 0xc002a03, 0x2003021, 
-0x3c024000, 0x2021024, 0x104000e1, 0x3c040100, 
-0x8f4203ac, 0x24420001, 0xaf4203ac, 0x8f4203ac, 
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 
-0x34420004, 0xaf820220, 0x8f8200e0, 0x8f8300c4, 
-0x3c02001f, 0x3442ffff, 0x24690008, 0x49102b, 
-0x10400003, 0x0, 0x8f42013c, 0x1224823, 
-0x8f8700c8, 0x8f840120, 0x8f830124, 0x10000005, 
-0x5821, 0x8f42012c, 0x62102b, 0x50400001, 
-0x27634800, 0x1083000d, 0x316200ff, 0x8c620018, 
-0x2442ffff, 0x2c420002, 0x5040fff6, 0x24630020, 
-0x8f4203c0, 0x240b0001, 0x24420001, 0xaf4203c0, 
-0x8f4203c0, 0x8c670008, 0x316200ff, 0x14400078, 
-0x0, 0x934205b5, 0x14400075, 0x0, 
-0x8f8500e4, 0x8f8200e0, 0x2403fff8, 0x433024, 
-0xc51023, 0x218c3, 0x4620001, 0x24630100, 
-0x8f8a00c4, 0x10600005, 0x24020001, 0x10620009, 
-0x0, 0x10000021, 0x0, 0x8f4203b0, 
-0x1403821, 0x24420001, 0xaf4203b0, 0x10000060, 
+0x8f8200e0, 0xafa20010, 0x8f8200e4, 0xafa20014, 
+0x8f8600c4, 0x8f8700c8, 0x3c040001, 0x24843a68, 
+0xc0029bb, 0x2002821, 0x3c044000, 0x2041024, 
+0x504000ae, 0x3c040100, 0x8f4203ac, 0x24420001, 
+0xaf4203ac, 0x8f4203ac, 0x8f8700c4, 0x8f8300c8, 
+0x8f42013c, 0x671823, 0x43102b, 0x10400003, 
+0x0, 0x8f42013c, 0x621821, 0x10600005, 
+0x0, 0x8f420140, 0x43102b, 0x10400007, 
+0x0, 0x8f820220, 0x3c0308ff, 0x3463fffb, 
+0x431024, 0x100000cc, 0x441025, 0x8f820220, 
+0x3c0308ff, 0x3463ffff, 0x431024, 0x34420004, 
+0xaf820220, 0x8f8600c8, 0x8f840120, 0x8f830124, 
+0x10000005, 0x2821, 0x14620002, 0x24620020, 
+0x27624800, 0x401821, 0x1064000c, 0x30a200ff, 
+0x8c620018, 0x30420003, 0x1040fff7, 0x27624fe0, 
+0x8f4203c0, 0x24050001, 0x24420001, 0xaf4203c0, 
+0x8f4203c0, 0x8c660008, 0x30a200ff, 0x14400058, 
+0x0, 0x934205b5, 0x14400055, 0x0, 
+0x8f8700c4, 0x8f8800e0, 0x8f8400e4, 0x2402fff8, 
+0x1024024, 0x1041023, 0x218c3, 0x4620001, 
+0x24630200, 0x10600005, 0x24020001, 0x10620009, 
+0x0, 0x1000001f, 0x0, 0x8f4203b0, 
+0xe03021, 0x24420001, 0xaf4203b0, 0x10000040, 
 0x8f4203b0, 0x8f4203b4, 0x24420001, 0xaf4203b4, 
-0x8ca70000, 0x8f42013c, 0x8f4303b4, 0x1471823, 
+0x8c860000, 0x8f42013c, 0x8f4303b4, 0xe61823, 
 0x43102b, 0x10400004, 0x2c62233f, 0x8f42013c, 
-0x621821, 0x2c62233f, 0x14400051, 0x3c020100, 
-0xaca20004, 0x8f8200e8, 0x24420008, 0xaf8200e8, 
-0x8f8200e8, 0x8f8200e4, 0x1403821, 0x24420008, 
-0xaf8200e4, 0x10000046, 0x8f8200e4, 0x8f4203b8, 
-0x24420001, 0xaf4203b8, 0x8ca80000, 0x8f42013c, 
-0x8f4303b8, 0x1092023, 0x44102b, 0x10400003, 
-0x0, 0x8f42013c, 0x822021, 0x8f420140, 
-0x44102b, 0x10400003, 0x3c030100, 0x10000034, 
-0x1003821, 0x8ca20004, 0x431025, 0xaca20004, 
-0x8f8200e4, 0x24450008, 0xaf8500e4, 0x8f8500e4, 
-0x10a60025, 0x3c080100, 0x8f4201fc, 0x24420001, 
-0xaf4201fc, 0x8ca20004, 0x8f4301fc, 0x481024, 
-0x1440000e, 0x0, 0x8ca30000, 0x8f42013c, 
-0x692023, 0x44102b, 0x10400003, 0x0, 
-0x8f42013c, 0x822021, 0x8f420140, 0x44102b, 
-0x10400006, 0x0, 0x603821, 0x8f420140, 
-0x44102b, 0x1440000a, 0x0, 0x8ca20004, 
-0x481025, 0xaca20004, 0x8f8200e4, 0x24450008, 
-0xaf8500e4, 0x8f8500e4, 0x14a6ffdf, 0x0, 
-0x14a60005, 0x0, 0x1403821, 0xaf8600e4, 
-0x10000003, 0xaf8600e8, 0xaf8500e4, 0xaf8500e8, 
-0x8f8300c8, 0x8f42013c, 0x692023, 0x44102b, 
-0x10400003, 0x0, 0x8f42013c, 0x822021, 
-0x8f420140, 0x82102b, 0x50400008, 0x5821, 
-0x8f42013c, 0xe92023, 0x44102b, 0x10400003, 
-0x0, 0x8f42013c, 0x822021, 0x8f420140, 
-0x82102b, 0x10400006, 0x316200ff, 0x1440001b, 
-0x3c02fdff, 0x934205b5, 0x14400018, 0x3c02fdff, 
-0xaf8700c8, 0x8f8400c8, 0x8f8300c4, 0x8f42013c, 
-0x832023, 0x44102b, 0x10400003, 0x0, 
-0x8f42013c, 0x822021, 0x8f420140, 0x2c830001, 
-0x44102b, 0x431025, 0x50400008, 0x3c02fdff, 
-0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 
-0x3c034000, 0x10000041, 0x431025, 0x3442ffff, 
-0x8f4303bc, 0x282a024, 0x24020001, 0xa34205b1, 
-0x24630001, 0xaf4303bc, 0x10000039, 0x8f4203bc, 
-0x2041024, 0x1040000e, 0x3c110200, 0x8f420398, 
-0x24420001, 0xaf420398, 0x8f420398, 0x8f820220, 
-0x3c0308ff, 0x3463ffff, 0x431024, 0x441025, 
-0xc003be0, 0xaf820220, 0x10000029, 0x0, 
-0x2111024, 0x50400008, 0x3c110400, 0x8f42039c, 
-0x24420001, 0xaf42039c, 0xc003be0, 0x8f42039c, 
-0x10000019, 0x0, 0x2111024, 0x1040001c, 
-0x0, 0x8f830224, 0x24021402, 0x14620009, 
-0x3c050008, 0x3c040001, 0x24843b14, 0xafa00010, 
-0xafa00014, 0x8f860224, 0x34a50500, 0xc002a03, 
-0x3821, 0x8f4203a0, 0x24420001, 0xaf4203a0, 
-0x8f4203a0, 0x8f820220, 0x2002021, 0x34420002, 
-0xc004640, 0xaf820220, 0x8f820220, 0x3c0308ff, 
-0x3463ffff, 0x431024, 0x511025, 0xaf820220, 
-0x8fbf0020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 
-0x27bd0028, 0x3e00008, 0x0, 0x3c020001, 
-0x8c423e38, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 
-0x1040000f, 0xafb00030, 0x3c040001, 0x24843b20, 
-0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, 
-0x34a50600, 0x24020001, 0x3c010001, 0xac203e38, 
-0x3c010001, 0xac223e2c, 0xc002a03, 0x3821, 
-0x3c037fff, 0x8c020268, 0x3463ffff, 0x3c04fdff, 
-0x431024, 0xac020268, 0x8f420004, 0x3484ffff, 
-0x30420002, 0x10400092, 0x284a024, 0x3c040600, 
-0x34842000, 0x8f420004, 0x2821, 0x2403fffd, 
-0x431024, 0xaf420004, 0xafa40020, 0x8f5e0018, 
-0x27aa0020, 0x240200ff, 0x13c20002, 0xafaa002c, 
-0x27c50001, 0x8c020228, 0xa09021, 0x1642000e, 
-0x1e38c0, 0x8f42032c, 0x24420001, 0xaf42032c, 
-0x8f42032c, 0x8c020228, 0x3c040001, 0x24843ab8, 
-0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 
-0x1000006d, 0x34a50500, 0xf71021, 0x8fa30020, 
-0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 
-0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, 
-0x1040001b, 0x9821, 0xe08821, 0x263504c0, 
-0x8f440168, 0x8f45016c, 0x2201821, 0x240a0004, 
-0xafaa0010, 0xafb20014, 0x8f48000c, 0x1021, 
-0x2f53021, 0xafa80018, 0x8f48010c, 0x24070008, 
-0xa32821, 0xa3482b, 0x822021, 0x100f809, 
-0x892021, 0x54400006, 0x24130001, 0x8f820054, 
-0x2021023, 0x2c4203e9, 0x1440ffe9, 0x0, 
-0x326200ff, 0x54400017, 0xaf520018, 0x8f420368, 
+0x621821, 0x2c62233f, 0x14400031, 0x0, 
+0x8f4201fc, 0x24420001, 0xaf4201fc, 0x8f4201fc, 
+0xe03021, 0x24820008, 0xaf8200e4, 0x10000028, 
+0xaf8200e8, 0x8f4203b8, 0x24420001, 0xaf4203b8, 
+0x8f4203b8, 0x8c850000, 0x8f42013c, 0xa71823, 
+0x43102b, 0x10400003, 0x0, 0x8f42013c, 
+0x621821, 0x8f420140, 0x43102b, 0x5440000a, 
+0xa03021, 0x8f4201fc, 0x24420001, 0xaf4201fc, 
+0x8f4201fc, 0x24820008, 0xaf8200e4, 0x8f8400e4, 
+0x1488ffec, 0xaf8400e8, 0x1488000d, 0x27623000, 
+0x14820002, 0x2482fff8, 0x27623ff8, 0x94430006, 
+0x3c02001f, 0x3442ffff, 0xc33021, 0x46102b, 
+0x10400003, 0x0, 0x8f42013c, 0xc23023, 
+0xaf8600c8, 0x8f8300c4, 0x8f42013c, 0xc31823, 
+0x43102b, 0x10400003, 0x0, 0x8f42013c, 
+0x621821, 0x10600005, 0x0, 0x8f420140, 
+0x43102b, 0x50400008, 0x3c02fdff, 0x8f820220, 
+0x3c0308ff, 0x3463fffb, 0x431024, 0x3c034000, 
+0x10000041, 0x431025, 0x3442ffff, 0x8f4303bc, 
+0x282a024, 0x24020001, 0xa34205b1, 0x24630001, 
+0xaf4303bc, 0x10000039, 0x8f4203bc, 0x2041024, 
+0x1040000e, 0x3c110200, 0x8f420398, 0x24420001, 
+0xaf420398, 0x8f420398, 0x8f820220, 0x3c0308ff, 
+0x3463ffff, 0x431024, 0x441025, 0xc003b0b, 
+0xaf820220, 0x10000029, 0x0, 0x2111024, 
+0x50400008, 0x3c110400, 0x8f42039c, 0x24420001, 
+0xaf42039c, 0xc003b0b, 0x8f42039c, 0x10000019, 
+0x0, 0x2111024, 0x1040001c, 0x0, 
+0x8f830224, 0x24021402, 0x14620009, 0x3c050008, 
+0x3c040001, 0x24843a74, 0xafa00010, 0xafa00014, 
+0x8f860224, 0x34a50500, 0xc0029bb, 0x3821, 
+0x8f4203a0, 0x24420001, 0xaf4203a0, 0x8f4203a0, 
+0x8f820220, 0x2002021, 0x34420002, 0xc00456c, 
+0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
+0x431024, 0x511025, 0xaf820220, 0x8fbf0020, 
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 
+0x3e00008, 0x0, 0x3c020001, 0x8c423d98, 
+0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040, 
+0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f, 
+0xafb00030, 0x3c040001, 0x24843a80, 0x3c050008, 
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600, 
+0x24020001, 0x3c010001, 0xac203d98, 0x3c010001, 
+0xac223d8c, 0xc0029bb, 0x3821, 0x3c037fff, 
+0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024, 
+0xac020268, 0x8f420004, 0x3484ffff, 0x30420002, 
+0x10400092, 0x284a024, 0x3c040600, 0x34842000, 
+0x8f420004, 0x2821, 0x2403fffd, 0x431024, 
+0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020, 
+0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001, 
+0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0, 
+0x8f42032c, 0x24420001, 0xaf42032c, 0x8f42032c, 
+0x8c020228, 0x3c040001, 0x24843a18, 0x3c050009, 
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, 
+0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 
+0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 
+0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, 
+0x9821, 0xe08821, 0x263504c0, 0x8f440168, 
+0x8f45016c, 0x2201821, 0x240a0004, 0xafaa0010, 
+0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, 
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
+0xa3482b, 0x822021, 0x100f809, 0x892021, 
+0x54400006, 0x24130001, 0x8f820054, 0x2021023, 
+0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 
+0x54400017, 0xaf520018, 0x8f420368, 0x24420001, 
+0xaf420368, 0x8f420368, 0x8f820120, 0x8faa002c, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x24843a24, 
+0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, 
+0x34a50600, 0x8f4202f8, 0x24130001, 0x24420001, 
+0xaf4202f8, 0x8f4202f8, 0x1000001e, 0x326200ff, 
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
+0x2c4203e9, 0x10400016, 0x9821, 0x3c150020, 
+0x24110010, 0x8f42000c, 0x8f440150, 0x8f450154, 
+0x8f860120, 0xafb10010, 0xafb20014, 0x551025, 
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, 
+0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054, 
+0x2021023, 0x2c4203e9, 0x1440ffee, 0x0, 
+0x326200ff, 0x14400011, 0x0, 0x8f420368, 
 0x24420001, 0xaf420368, 0x8f420368, 0x8f820120, 
 0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24843ac4, 0x3c050009, 0xafa20014, 0x8d460000, 
-0x10000035, 0x34a50600, 0x8f4202f8, 0x24130001, 
-0x24420001, 0xaf4202f8, 0x8f4202f8, 0x1000001e, 
-0x326200ff, 0x8f830054, 0x8f820054, 0x247003e8, 
-0x2021023, 0x2c4203e9, 0x10400016, 0x9821, 
-0x3c150020, 0x24110010, 0x8f42000c, 0x8f440150, 
-0x8f450154, 0x8f860120, 0xafb10010, 0xafb20014, 
-0x551025, 0xafa20018, 0x8f42010c, 0x24070008, 
-0x40f809, 0x24c6001c, 0x1440ffe3, 0x0, 
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffee, 
-0x0, 0x326200ff, 0x14400011, 0x0, 
-0x8f420368, 0x24420001, 0xaf420368, 0x8f420368, 
-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x24843acc, 0x3c050009, 0xafa20014, 
-0x8d460000, 0x34a50700, 0xc002a03, 0x3c03821, 
-0x8f4202dc, 0x24420001, 0xaf4202dc, 0x8f4202dc, 
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 
-0x27bd0050, 0x3c020001, 0x8c423e38, 0x27bdffe0, 
-0x1440000d, 0xafbf0018, 0x3c040001, 0x24843b2c, 
-0x3c050008, 0xafa00010, 0xafa00014, 0x8f860220, 
-0x34a50700, 0x24020001, 0x3c010001, 0xac223e38, 
-0xc002a03, 0x3821, 0x3c020004, 0x2c21024, 
-0x10400008, 0x2021, 0x8f820220, 0x3c0308ff, 
-0x3463ffff, 0x431024, 0x34420008, 0xaf820220, 
-0x2021, 0xc0049b1, 0x24050004, 0xac020268, 
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x86102b, 
+0x24843a2c, 0x3c050009, 0xafa20014, 0x8d460000, 
+0x34a50700, 0xc0029bb, 0x3c03821, 0x8f4202dc, 
+0x24420001, 0xaf4202dc, 0x8f4202dc, 0x8fbf0048, 
+0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038, 
+0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, 
+0x3c020001, 0x8c423d98, 0x27bdffe0, 0x1440000d, 
+0xafbf0018, 0x3c040001, 0x24843a8c, 0x3c050008, 
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700, 
+0x24020001, 0x3c010001, 0xac223d98, 0xc0029bb, 
+0x3821, 0x3c020004, 0x2c21024, 0x10400008, 
+0x2021, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
+0x431024, 0x34420008, 0xaf820220, 0x2021, 
+0xc0048dd, 0x24050004, 0xac020268, 0x8fbf0018, 
+0x3e00008, 0x27bd0020, 0x0, 0x86102b, 
 0x50400001, 0x872023, 0xc41023, 0x24843, 
 0x125102b, 0x1040001b, 0x91040, 0x824021, 
 0x88102b, 0x10400007, 0x1821, 0x94820000, 
@@ -7372,7 +7329,7 @@
 0x90a20000, 0x822021, 0x41c02, 0x3082ffff, 
 0x622021, 0x41c02, 0x3082ffff, 0x622021, 
 0x3e00008, 0x3082ffff, 0x0, 0x8f820220, 
-0x34420002, 0xaf820220, 0x3c020001, 0x8c426038, 
+0x34420002, 0xaf820220, 0x3c020001, 0x8c425f98, 
 0x30424000, 0x10400054, 0x24040001, 0x8f820200, 
 0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, 
 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, 
@@ -7419,501 +7376,501 @@
 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 
 0x10620008, 0x24020800, 0x10000008, 0x0, 
 0x10620004, 0x24020800, 0x10000004, 0x0, 
-0x24020700, 0x3c010001, 0xac223e3c, 0x3e00008, 
+0x24020700, 0x3c010001, 0xac223d9c, 0x3e00008, 
 0x0, 0x27bdffc8, 0xafbf0034, 0xafb20030, 
-0xafb1002c, 0xafb00028, 0x3c010001, 0xc00461d, 
-0xac203e24, 0x24040001, 0x2821, 0x27a60020, 
-0x34028000, 0xc00423a, 0xa7a20020, 0x8f830054, 
+0xafb1002c, 0xafb00028, 0x3c010001, 0xc004549, 
+0xac203d84, 0x24040001, 0x2821, 0x27a60020, 
+0x34028000, 0xc004166, 0xa7a20020, 0x8f830054, 
 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, 
+0x24050001, 0xc004124, 0x27a60020, 0x8f830054, 
 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050001, 0xc0041f8, 0x27a60020, 0x8f830054, 
+0x24050001, 0xc004124, 0x27a60020, 0x8f830054, 
 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050002, 0xc0041f8, 0x27a60018, 0x8f830054, 
+0x24050002, 0xc004124, 0x27a60018, 0x8f830054, 
 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
 0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050003, 0xc0041f8, 0x27a6001a, 0x97a20020, 
-0x10400029, 0x24020001, 0x3c020001, 0x8c423e24, 
-0x97a30018, 0x34420001, 0x3c010001, 0xac223e24, 
-0x24020015, 0x14620009, 0x0, 0x97a2001a, 
-0x3843f423, 0x2c630001, 0x3842f430, 0x2c420001, 
-0x621825, 0x14600018, 0x24020003, 0x97a30018, 
-0x24027810, 0x14620014, 0x24020002, 0x97a3001a, 
-0x24020001, 0x14620010, 0x24020002, 0x1000000e, 
-0x24020004, 0x3c020001, 0x8c423e24, 0x34420008, 
-0x3c010001, 0xac223e24, 0x10000058, 0x24020004, 
-0x3c020001, 0x8c423e24, 0x34420004, 0x3c010001, 
-0x100000a9, 0xac223e24, 0x3c010001, 0xac223f80, 
-0x24020e00, 0xaf820238, 0x8f840054, 0x8f820054, 
-0x24030008, 0x3c010001, 0xac233e28, 0x10000002, 
-0x248401f4, 0x8f820054, 0x821023, 0x2c4201f5, 
-0x1440fffc, 0x3c0200c8, 0x344201fb, 0xaf820238, 
-0x8f830054, 0x8f820054, 0x10000002, 0x246301f4, 
-0x8f820054, 0x621023, 0x2c4201f5, 0x1440fffc, 
-0x8021, 0x24120001, 0x24110009, 0xc004118, 
-0x0, 0x3c010001, 0xac323e40, 0xc0041c4, 
-0x0, 0x3c020001, 0x8c423e40, 0x1451fffb, 
-0x3c0200c8, 0x344201f6, 0xaf820238, 0x8f830054, 
-0x8f820054, 0x10000002, 0x2463000a, 0x8f820054, 
-0x621023, 0x2c42000b, 0x1440fffc, 0x0, 
+0x24050003, 0xc004124, 0x27a6001a, 0x97a20020, 
+0x1040002a, 0x24020001, 0x3c020001, 0x8c423d84, 
+0x97a30018, 0x34420001, 0x3c010001, 0xac223d84, 
+0x24020015, 0x1462000a, 0x0, 0x97a2001a, 
+0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430, 
+0x2c420001, 0x621825, 0x14600018, 0x24020003, 
+0x97a30018, 0x24027810, 0x14620014, 0x24020002, 
+0x97a2001a, 0x3042fff0, 0x14400010, 0x24020002, 
+0x1000000e, 0x24020004, 0x3c020001, 0x8c423d84, 
+0x34420008, 0x3c010001, 0xac223d84, 0x10000058, 
+0x24020004, 0x3c020001, 0x8c423d84, 0x34420004, 
+0x3c010001, 0x100000a9, 0xac223d84, 0x3c010001, 
+0xac223ee0, 0x24020e00, 0xaf820238, 0x8f840054, 
+0x8f820054, 0x24030008, 0x3c010001, 0xac233d88, 
+0x10000002, 0x248401f4, 0x8f820054, 0x821023, 
+0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb, 
+0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, 
+0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, 
+0x1440fffc, 0x8021, 0x24120001, 0x24110009, 
+0xc004045, 0x0, 0x3c010001, 0xac323da0, 
+0xc0040f2, 0x0, 0x3c020001, 0x8c423da0, 
+0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238, 
+0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 
+0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, 
+0x0, 0x8f820220, 0x24040001, 0x34420002, 
+0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd, 
+0x621824, 0xaf830200, 0xaf840204, 0x8f830054, 
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 
+0x621023, 0x2c420002, 0x1440fffc, 0x0, 
+0x8f820224, 0x14440005, 0x34028000, 0x42040, 
+0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa6, 
+0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004, 
+0x3c010001, 0xac223d88, 0x8021, 0x24120009, 
+0x3c11ffff, 0x36313f7f, 0xc004045, 0x0, 
+0x24020001, 0x3c010001, 0xac223da0, 0xc0040f2, 
+0x0, 0x3c020001, 0x8c423da0, 0x1452fffb, 
+0x0, 0x8f820044, 0x511024, 0x34425080, 
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 
+0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, 
+0x1440fffc, 0x0, 0x8f820044, 0x511024, 
+0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054, 
+0x10000002, 0x2463000a, 0x8f820054, 0x621023, 
+0x2c42000b, 0x1440fffc, 0x0, 0x8f820220, 
+0x3c03f700, 0x431025, 0xaf820220, 0x8f830054, 
+0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
+0x621023, 0x2c420065, 0x1440fffc, 0x0, 
 0x8f820220, 0x24040001, 0x34420002, 0xaf820220, 
 0x8f830200, 0x24057fff, 0x2402fffd, 0x621824, 
 0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054, 
 0x10000002, 0x24630001, 0x8f820054, 0x621023, 
 0x2c420002, 0x1440fffc, 0x0, 0x8f820224, 
 0x14440005, 0x34028000, 0x42040, 0xa4102b, 
-0x1040fff0, 0x34028000, 0x1082ffa6, 0x26100001, 
-0x2e020014, 0x1440ffcd, 0x24020004, 0x3c010001, 
-0xac223e28, 0x8021, 0x24120009, 0x3c11ffff, 
-0x36313f7f, 0xc004118, 0x0, 0x24020001, 
-0x3c010001, 0xac223e40, 0xc0041c4, 0x0, 
-0x3c020001, 0x8c423e40, 0x1452fffb, 0x0, 
-0x8f820044, 0x511024, 0x34425080, 0xaf820044, 
-0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, 
-0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, 
-0x0, 0x8f820044, 0x511024, 0x3442f080, 
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 
-0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, 
-0x1440fffc, 0x0, 0x8f820220, 0x3c03f700, 
-0x431025, 0xaf820220, 0x8f830054, 0x8f820054, 
-0x10000002, 0x24630064, 0x8f820054, 0x621023, 
-0x2c420065, 0x1440fffc, 0x0, 0x8f820220, 
-0x24040001, 0x34420002, 0xaf820220, 0x8f830200, 
-0x24057fff, 0x2402fffd, 0x621824, 0xaf830200, 
-0xaf840204, 0x8f830054, 0x8f820054, 0x10000002, 
-0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
-0x1440fffc, 0x0, 0x8f820224, 0x14440005, 
-0x34028000, 0x42040, 0xa4102b, 0x1040fff0, 
-0x34028000, 0x1082ff56, 0x26100001, 0x2e020064, 
-0x1440ffb0, 0x0, 0x3c020001, 0x8c423e24, 
-0x30420004, 0x14400007, 0x3c08fff0, 0x8f820044, 
-0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, 
-0x3c08fff0, 0x3508bdc0, 0x8f830054, 0x97a60018, 
-0x3c070001, 0x8ce73f80, 0x3c040001, 0x24843c00, 
-0x24020001, 0x3c010001, 0xac223e2c, 0xafa60010, 
-0x3c060001, 0x8cc63e24, 0x97a2001a, 0x3c05000d, 
-0x34a50100, 0x3c010001, 0xac203e28, 0x681821, 
-0x3c010001, 0xac233f78, 0xc002a03, 0xafa20014, 
-0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 
-0x3e00008, 0x27bd0038, 0x27bdffe8, 0x24070004, 
-0x3c040001, 0x8c843e28, 0x3021, 0x24020001, 
-0x1482000a, 0xafbf0010, 0x3c020001, 0x8c42603c, 
-0x3c050004, 0x30428000, 0x1040000c, 0x34a593e0, 
-0x3c05000f, 0x10000009, 0x34a54240, 0x3c020001, 
-0x8c42603c, 0x3c05000f, 0x30428000, 0x10400003, 
-0x34a54240, 0x3c05001e, 0x34a58480, 0x3c020001, 
-0x8c423f78, 0x8f830054, 0x451021, 0x431023, 
-0x45102b, 0x1440002e, 0x0, 0x3c020001, 
-0x8c423e30, 0x1440002a, 0x2cc20001, 0x7182b, 
-0x431024, 0x1040001d, 0x0, 0x3c090001, 
-0x8d293e24, 0x240b0001, 0x3c054000, 0x3c080001, 
-0x2508603c, 0x250afffc, 0x42042, 0x14800002, 
-0x24e7ffff, 0x24040008, 0x891024, 0x5040000b, 
-0x2cc20001, 0x148b0004, 0x0, 0x8d020000, 
-0x10000003, 0x451024, 0x8d420000, 0x451024, 
-0x54400001, 0x24060001, 0x2cc20001, 0x7182b, 
-0x431024, 0x5440ffed, 0x42042, 0x3c010001, 
-0x10c00020, 0xac243e28, 0x8f830054, 0x24020001, 
-0x3c010001, 0xac223e2c, 0x3c010001, 0xac233f78, 
-0x3c020001, 0x8c423e2c, 0x10400004, 0x24020001, 
-0x3c010001, 0xac203e2c, 0xaee204b8, 0x8ee304b8, 
-0x24020008, 0x10620005, 0x24020001, 0xc003fc1, 
-0x0, 0x1000000b, 0x0, 0x3c030001, 
-0x8c633e28, 0x10620007, 0x2402000e, 0x3c030001, 
-0x8c635fd0, 0x10620003, 0x0, 0xc004640, 
-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 
-0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c843e28, 
-0x3c020001, 0x8c423e48, 0x3463ffff, 0x283a024, 
-0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, 
-0x8c423e4c, 0x10620006, 0x0, 0x8ee204b8, 
-0x3c010001, 0xac243e48, 0x3c010001, 0xac223e4c, 
-0x3c030001, 0x8c633e28, 0x24020002, 0x1062013c, 
-0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 
-0x0, 0x10000134, 0x0, 0x24020004, 
-0x1062006d, 0x24020008, 0x1062009f, 0x24020001, 
-0x1000012d, 0x0, 0x8ee204b8, 0x2443ffff, 
-0x2c620008, 0x1040012a, 0x31080, 0x3c010001, 
-0x220821, 0x8c223c18, 0x400008, 0x0, 
-0xc004118, 0x0, 0x3c020001, 0x8c423e34, 
-0x3c010001, 0xac203dc0, 0x104000d7, 0x24020002, 
-0xaee204b8, 0x3c010001, 0x10000119, 0xac203e34, 
-0xc00427b, 0x0, 0x3c030001, 0x8c633e50, 
-0x1000009e, 0x24020011, 0x3c050001, 0x8ca53e28, 
-0x3c060001, 0x8cc6603c, 0xc0048a8, 0x2021, 
-0x24020005, 0x3c010001, 0xac203e34, 0x10000108, 
-0xaee204b8, 0x3c040001, 0x24843c0c, 0x3c05000f, 
-0x34a50100, 0x3021, 0x3821, 0xafa00010, 
-0xc002a03, 0xafa00014, 0x100000fd, 0x0, 
-0x8f820220, 0x3c03f700, 0x431025, 0x100000a4, 
-0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 
-0x144000ae, 0x24020007, 0x8f830054, 0x3c020001, 
-0x8c423f70, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x144000eb, 0x24020001, 0x100000e7, 0x0, 
-0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, 
-0xc004a7c, 0x2021, 0x3c030001, 0x8c636034, 
-0x46100dd, 0x24020001, 0x3c020008, 0x621024, 
-0x10400006, 0x0, 0x8f820214, 0x3c03ffff, 
-0x431024, 0x10000005, 0x3442251f, 0x8f820214, 
-0x3c03ffff, 0x431024, 0x3442241f, 0xaf820214, 
-0x8f820220, 0x3c030200, 0x283a025, 0x34420002, 
-0xaf820220, 0x24020008, 0xc003c9e, 0xaee204b8, 
-0x100000c7, 0x0, 0x8ee204b8, 0x2443ffff, 
-0x2c620008, 0x104000c2, 0x31080, 0x3c010001, 
-0x220821, 0x8c223c38, 0x400008, 0x0, 
-0x3c020001, 0x8c426038, 0x30424000, 0x10400004, 
-0x0, 0x8f820044, 0x10000006, 0x3442f080, 
+0x1040fff0, 0x34028000, 0x1082ff56, 0x26100001, 
+0x2e020064, 0x1440ffb0, 0x0, 0x3c020001, 
+0x8c423d84, 0x30420004, 0x14400007, 0x3c08fff0, 
 0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 
-0x3442a080, 0xaf820044, 0x8f830054, 0x1000005a, 
-0x24020004, 0xc003d5c, 0x0, 0x104000a6, 
-0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, 
-0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, 
-0x24020008, 0x10800005, 0xaee204b8, 0x3c020001, 
-0x8c423eb4, 0x1040006d, 0x24020001, 0x8f820220, 
-0x3c030008, 0x431024, 0x10400073, 0x3c020200, 
-0x10000081, 0x0, 0x8ee204b8, 0x2443ffff, 
-0x2c620007, 0x1040008e, 0x31080, 0x3c010001, 
-0x220821, 0x8c223c58, 0x400008, 0x0, 
-0xc003be0, 0x0, 0x3c010001, 0xac203e2c, 
-0xaf800204, 0x3c010001, 0xc004118, 0xac206020, 
-0x24020001, 0x3c010001, 0xac223e40, 0x24020002, 
-0x1000007b, 0xaee204b8, 0xc0041c4, 0x0, 
-0x3c030001, 0x8c633e40, 0x24020009, 0x14620074, 
-0x24020003, 0x10000072, 0xaee204b8, 0x3c020001, 
-0x8c426038, 0x30424000, 0x10400003, 0x3c0200c8, 
-0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, 
-0x8f830054, 0x10000014, 0x24020004, 0x8f830054, 
-0x3c020001, 0x8c423f70, 0x2463d8f0, 0x431023, 
-0x2c422710, 0x1440005e, 0x24020005, 0x1000005c, 
-0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025, 
-0xaf820220, 0xaf800204, 0x3c010001, 0xac206020, 
-0x8f830054, 0x24020006, 0xaee204b8, 0x3c010001, 
-0x1000004f, 0xac233f70, 0x8f830054, 0x3c020001, 
-0x8c423f70, 0x2463fff6, 0x431023, 0x2c42000a, 
-0x14400047, 0x0, 0x24020007, 0x10000044, 
-0xaee204b8, 0xc003d5c, 0x0, 0x1040003e, 
-0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, 
-0x8c843f68, 0x431024, 0x3442251f, 0xaf820214, 
-0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001, 
-0x8c423eb4, 0x1440000b, 0x0, 0x8f820220, 
-0x34420002, 0xaf820220, 0x24020001, 0x3c010001, 
-0xac225fd0, 0xc004640, 0x8f840220, 0x10000016, 
-0x0, 0x8f820220, 0x3c030008, 0x431024, 
-0x14400011, 0x3c020200, 0x282a025, 0x2402000e, 
-0x3c010001, 0xac225fd0, 0xc004a7c, 0x2021, 
-0x8f820220, 0x34420002, 0xc003c9e, 0xaf820220, 
-0x3c050001, 0x8ca53e28, 0xc0049b1, 0x2021, 
-0x10000013, 0x0, 0x3c020001, 0x8c423eb4, 
-0x1040000f, 0x0, 0x3c020001, 0x8c423eb0, 
-0x2442ffff, 0x3c010001, 0xac223eb0, 0x14400008, 
-0x24020002, 0x3c010001, 0xac203eb4, 0x3c010001, 
-0x10000003, 0xac223eb0, 0x3c010001, 0xac223e2c, 
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x8f820200, 
-0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, 
-0x8f820200, 0x3c040001, 0x8c843e28, 0x34420004, 
-0xaf820200, 0x24020002, 0x1082003a, 0x2c820003, 
-0x10400005, 0x24020001, 0x1082000a, 0x3c03f0ff, 
-0x10000098, 0x0, 0x24020004, 0x10820059, 
-0x24020008, 0x1082006c, 0x3c02f0ff, 0x10000091, 
-0x0, 0x8f820050, 0x3463ffff, 0x3c05ffff, 
-0x34a53f7f, 0x431024, 0x3c030700, 0x431025, 
-0xaf820050, 0x24020e00, 0xaf840200, 0xaf840220, 
-0xaf820238, 0x8f820044, 0x3c030001, 0x8c633e18, 
-0x3c040001, 0x8c843f80, 0x451024, 0x34630022, 
-0xaf820044, 0x24020004, 0x1082000c, 0xaf830200, 
-0x3c020001, 0x8c423e3c, 0x3c030001, 0x8c633e20, 
-0x3c040001, 0x8c843e1c, 0x34428000, 0x621825, 
-0x641825, 0x1000006e, 0x34620002, 0x3c020001, 
-0x8c423e20, 0x3c030001, 0x8c633e3c, 0x3c040001, 
-0x8c843e1c, 0x431025, 0x441025, 0x10000064, 
-0x34420002, 0x8f830050, 0x3c02f0ff, 0x3442ffff, 
-0x3c040001, 0x8c843f68, 0x621824, 0x3c020d00, 
-0x621825, 0x24020001, 0xaf830050, 0xaf820200, 
-0xaf820220, 0x24020e00, 0x10800009, 0xaf820238, 
-0x3c020001, 0x8c423eb4, 0x14400005, 0x3c033f00, 
-0x3c020001, 0x8c423e10, 0x10000005, 0x34630070, 
-0x3c020001, 0x8c423e10, 0x3c033f00, 0x34630072, 
-0x431025, 0xaf820200, 0x3c030001, 0x8c633e14, 
-0x3c04f700, 0x3c020001, 0x8c423e20, 0x3c050001, 
-0x8ca53e3c, 0x641825, 0x431025, 0x1000003c, 
-0x451025, 0x8f830050, 0x3c02f0ff, 0x3442ffff, 
-0x3c040001, 0x8c843f68, 0x621824, 0x3c020a00, 
-0x621825, 0x24020001, 0xaf830050, 0xaf820200, 
-0x1080001e, 0xaf820220, 0x3c020001, 0x8c423eb4, 
-0x1440001a, 0x3c033f00, 0x3c020001, 0x8c423e10, 
-0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001, 
-0x8c843f68, 0x3442ffff, 0x621824, 0x1080000f, 
-0xaf830050, 0x3c020001, 0x8c423eb4, 0x1440000b, 
-0x3c043f00, 0x3c030001, 0x8c633e10, 0x348400e0, 
-0x24020001, 0xaf820200, 0xaf820220, 0x641825, 
-0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001, 
-0x8c423e10, 0x3c033f00, 0x346300e2, 0x431025, 
-0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001, 
-0x8c633e14, 0x3c020001, 0x8c423e20, 0x3c040001, 
-0x8c843e3c, 0x651825, 0x431025, 0x441025, 
-0xaf820220, 0x3e00008, 0x0, 0x3c030001, 
-0x8c633e40, 0x3c020001, 0x8c423e44, 0x10620003, 
-0x24020002, 0x3c010001, 0xac233e44, 0x1062001d, 
-0x2c620003, 0x10400025, 0x24020001, 0x14620023, 
-0x24020004, 0x3c030001, 0x8c633e28, 0x10620006, 
-0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb, 
-0x10000009, 0xaf820238, 0x24020e01, 0xaf820238, 
-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 
-0x34420080, 0xaf820044, 0x8f830054, 0x24020002, 
-0x3c010001, 0xac223e40, 0x3c010001, 0x1000000b, 
-0xac233f74, 0x8f830054, 0x3c020001, 0x8c423f74, 
-0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, 
-0x24020009, 0x3c010001, 0xac223e40, 0x3e00008, 
-0x0, 0x0, 0x0, 0x27bdffd8, 
+0xaf820044, 0x3c08fff0, 0x3508bdc0, 0x8f830054, 
+0x97a60018, 0x3c070001, 0x8ce73ee0, 0x3c040001, 
+0x24843b60, 0x24020001, 0x3c010001, 0xac223d8c, 
+0xafa60010, 0x3c060001, 0x8cc63d84, 0x97a2001a, 
+0x3c05000d, 0x34a50100, 0x3c010001, 0xac203d88, 
+0x681821, 0x3c010001, 0xac233ed8, 0xc0029bb, 
+0xafa20014, 0x8fbf0034, 0x8fb20030, 0x8fb1002c, 
+0x8fb00028, 0x3e00008, 0x27bd0038, 0x27bdffe8, 
+0x24070004, 0x3c040001, 0x8c843d88, 0x3021, 
+0x24020001, 0x1482000a, 0xafbf0010, 0x3c020001, 
+0x8c425f9c, 0x3c050004, 0x30428000, 0x1040000c, 
+0x34a593e0, 0x3c05000f, 0x10000009, 0x34a54240, 
+0x3c020001, 0x8c425f9c, 0x3c05000f, 0x30428000, 
+0x10400003, 0x34a54240, 0x3c05001e, 0x34a58480, 
+0x3c020001, 0x8c423ed8, 0x8f830054, 0x451021, 
+0x431023, 0x45102b, 0x1440002e, 0x0, 
+0x3c020001, 0x8c423d90, 0x1440002a, 0x2cc20001, 
+0x7182b, 0x431024, 0x1040001d, 0x0, 
+0x3c090001, 0x8d293d84, 0x240b0001, 0x3c054000, 
+0x3c080001, 0x25085f9c, 0x250afffc, 0x42042, 
+0x14800002, 0x24e7ffff, 0x24040008, 0x891024, 
+0x5040000b, 0x2cc20001, 0x148b0004, 0x0, 
+0x8d020000, 0x10000003, 0x451024, 0x8d420000, 
+0x451024, 0x54400001, 0x24060001, 0x2cc20001, 
+0x7182b, 0x431024, 0x5440ffed, 0x42042, 
+0x3c010001, 0x10c00020, 0xac243d88, 0x8f830054, 
+0x24020001, 0x3c010001, 0xac223d8c, 0x3c010001, 
+0xac233ed8, 0x3c020001, 0x8c423d8c, 0x10400004, 
+0x24020001, 0x3c010001, 0xac203d8c, 0xaee204b8, 
+0x8ee304b8, 0x24020008, 0x10620005, 0x24020001, 
+0xc003eee, 0x0, 0x1000000b, 0x0, 
+0x3c030001, 0x8c633d88, 0x10620007, 0x2402000e, 
+0x3c030001, 0x8c635f30, 0x10620003, 0x0, 
+0xc00456c, 0x8f840220, 0x8fbf0010, 0x3e00008, 
+0x27bd0018, 0x27bdffe0, 0x3c03fdff, 0x3c040001, 
+0x8c843d88, 0x3c020001, 0x8c423da8, 0x3463ffff, 
+0x283a024, 0x14820006, 0xafbf0018, 0x8ee304b8, 
+0x3c020001, 0x8c423dac, 0x10620006, 0x0, 
+0x8ee204b8, 0x3c010001, 0xac243da8, 0x3c010001, 
+0xac223dac, 0x3c030001, 0x8c633d88, 0x24020002, 
+0x1062013c, 0x2c620003, 0x10400005, 0x24020001, 
+0x1062000a, 0x0, 0x10000134, 0x0, 
+0x24020004, 0x1062006d, 0x24020008, 0x1062009f, 
+0x24020001, 0x1000012d, 0x0, 0x8ee204b8, 
+0x2443ffff, 0x2c620008, 0x1040012a, 0x31080, 
+0x3c010001, 0x220821, 0x8c223b78, 0x400008, 
+0x0, 0xc004045, 0x0, 0x3c020001, 
+0x8c423d94, 0x3c010001, 0xac203d20, 0x104000d7, 
+0x24020002, 0xaee204b8, 0x3c010001, 0x10000119, 
+0xac203d94, 0xc0041a7, 0x0, 0x3c030001, 
+0x8c633db0, 0x1000009e, 0x24020011, 0x3c050001, 
+0x8ca53d88, 0x3c060001, 0x8cc65f9c, 0xc0047d4, 
+0x2021, 0x24020005, 0x3c010001, 0xac203d94, 
+0x10000108, 0xaee204b8, 0x3c040001, 0x24843b6c, 
+0x3c05000f, 0x34a50100, 0x3021, 0x3821, 
+0xafa00010, 0xc0029bb, 0xafa00014, 0x100000fd, 
+0x0, 0x8f820220, 0x3c03f700, 0x431025, 
+0x100000a4, 0xaf820220, 0x8f820220, 0x3c030004, 
+0x431024, 0x144000ae, 0x24020007, 0x8f830054, 
+0x3c020001, 0x8c423ed0, 0x2463d8f0, 0x431023, 
+0x2c422710, 0x144000eb, 0x24020001, 0x100000e7, 
+0x0, 0x3c050001, 0x8ca53d88, 0xc0048dd, 
+0x2021, 0xc0049a8, 0x2021, 0x3c030001, 
+0x8c635f94, 0x46100dd, 0x24020001, 0x3c020008, 
+0x621024, 0x10400006, 0x0, 0x8f820214, 
+0x3c03ffff, 0x431024, 0x10000005, 0x3442251f, 
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, 
+0xaf820214, 0x8f820220, 0x3c030200, 0x283a025, 
+0x34420002, 0xaf820220, 0x24020008, 0xc003bc9, 
+0xaee204b8, 0x100000c7, 0x0, 0x8ee204b8, 
+0x2443ffff, 0x2c620008, 0x104000c2, 0x31080, 
+0x3c010001, 0x220821, 0x8c223b98, 0x400008, 
+0x0, 0x3c020001, 0x8c425f98, 0x30424000, 
+0x10400004, 0x0, 0x8f820044, 0x10000006, 
+0x3442f080, 0x8f820044, 0x3c03ffff, 0x34633f7f, 
+0x431024, 0x3442a080, 0xaf820044, 0x8f830054, 
+0x1000005a, 0x24020004, 0xc003c88, 0x0, 
+0x104000a6, 0x24020001, 0x8f820214, 0x3c03ffff, 
+0x3c040001, 0x8c843ec8, 0x431024, 0x3442251f, 
+0xaf820214, 0x24020008, 0x10800005, 0xaee204b8, 
+0x3c020001, 0x8c423e14, 0x1040006d, 0x24020001, 
+0x8f820220, 0x3c030008, 0x431024, 0x10400073, 
+0x3c020200, 0x10000081, 0x0, 0x8ee204b8, 
+0x2443ffff, 0x2c620007, 0x1040008e, 0x31080, 
+0x3c010001, 0x220821, 0x8c223bb8, 0x400008, 
+0x0, 0xc003b0b, 0x0, 0x3c010001, 
+0xac203d8c, 0xaf800204, 0x3c010001, 0xc004045, 
+0xac205f80, 0x24020001, 0x3c010001, 0xac223da0, 
+0x24020002, 0x1000007b, 0xaee204b8, 0xc0040f2, 
+0x0, 0x3c030001, 0x8c633da0, 0x24020009, 
+0x14620074, 0x24020003, 0x10000072, 0xaee204b8, 
+0x3c020001, 0x8c425f98, 0x30424000, 0x10400003, 
+0x3c0200c8, 0x10000002, 0x344201f6, 0x344201fe, 
+0xaf820238, 0x8f830054, 0x10000014, 0x24020004, 
+0x8f830054, 0x3c020001, 0x8c423ed0, 0x2463d8f0, 
+0x431023, 0x2c422710, 0x1440005e, 0x24020005, 
+0x1000005c, 0xaee204b8, 0x8f820220, 0x3c03f700, 
+0x431025, 0xaf820220, 0xaf800204, 0x3c010001, 
+0xac205f80, 0x8f830054, 0x24020006, 0xaee204b8, 
+0x3c010001, 0x1000004f, 0xac233ed0, 0x8f830054, 
+0x3c020001, 0x8c423ed0, 0x2463fff6, 0x431023, 
+0x2c42000a, 0x14400047, 0x0, 0x24020007, 
+0x10000044, 0xaee204b8, 0xc003c88, 0x0, 
+0x1040003e, 0x24020001, 0x8f820214, 0x3c03ffff, 
+0x3c040001, 0x8c843ec8, 0x431024, 0x3442251f, 
+0xaf820214, 0x24020008, 0x1080000f, 0xaee204b8, 
+0x3c020001, 0x8c423e14, 0x1440000b, 0x0, 
+0x8f820220, 0x34420002, 0xaf820220, 0x24020001, 
+0x3c010001, 0xac225f30, 0xc00456c, 0x8f840220, 
+0x10000016, 0x0, 0x8f820220, 0x3c030008, 
+0x431024, 0x14400011, 0x3c020200, 0x282a025, 
+0x2402000e, 0x3c010001, 0xac225f30, 0xc0049a8, 
+0x2021, 0x8f820220, 0x34420002, 0xc003bc9, 
+0xaf820220, 0x3c050001, 0x8ca53d88, 0xc0048dd, 
+0x2021, 0x10000013, 0x0, 0x3c020001, 
+0x8c423e14, 0x1040000f, 0x0, 0x3c020001, 
+0x8c423e10, 0x2442ffff, 0x3c010001, 0xac223e10, 
+0x14400008, 0x24020002, 0x3c010001, 0xac203e14, 
+0x3c010001, 0x10000003, 0xac223e10, 0x3c010001, 
+0xac223d8c, 0x8fbf0018, 0x3e00008, 0x27bd0020, 
+0x8f820200, 0x8f820220, 0x8f820220, 0x34420004, 
+0xaf820220, 0x8f820200, 0x3c060001, 0x8cc63d88, 
+0x34420004, 0xaf820200, 0x24020002, 0x10c2003b, 
+0x2cc20003, 0x10400005, 0x24020001, 0x10c2000a, 
+0x3c03f0ff, 0x10000099, 0x0, 0x24020004, 
+0x10c2005a, 0x24020008, 0x10c2006d, 0x3c02f0ff, 
+0x10000092, 0x0, 0x8f820050, 0x3463ffff, 
+0x3c05ffff, 0x3c040001, 0x8c843ee0, 0x431024, 
+0x3c030700, 0x431025, 0xaf820050, 0x24020e00, 
+0xaf860200, 0xaf860220, 0xaf820238, 0x8f820044, 
+0x3c030001, 0x8c633d78, 0x34a53f7f, 0x451024, 
+0x34630022, 0xaf820044, 0x24020004, 0xaf860238, 
+0x1082000c, 0xaf830200, 0x3c020001, 0x8c423d9c, 
+0x3c030001, 0x8c633d80, 0x3c040001, 0x8c843d7c, 
+0x34428000, 0x621825, 0x641825, 0x1000006e, 
+0x34620002, 0x3c020001, 0x8c423d80, 0x3c030001, 
+0x8c633d9c, 0x3c040001, 0x8c843d7c, 0x431025, 
+0x441025, 0x10000064, 0x34420002, 0x8f830050, 
+0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843ec8, 
+0x621824, 0x3c020d00, 0x621825, 0x24020001, 
+0xaf830050, 0xaf820200, 0xaf820220, 0x24020e00, 
+0x10800009, 0xaf820238, 0x3c020001, 0x8c423e14, 
+0x14400005, 0x3c033f00, 0x3c020001, 0x8c423d70, 
+0x10000005, 0x34630070, 0x3c020001, 0x8c423d70, 
+0x3c033f00, 0x34630072, 0x431025, 0xaf820200, 
+0x3c030001, 0x8c633d74, 0x3c04f700, 0x3c020001, 
+0x8c423d80, 0x3c050001, 0x8ca53d9c, 0x641825, 
+0x431025, 0x1000003c, 0x451025, 0x8f830050, 
+0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c843ec8, 
+0x621824, 0x3c020a00, 0x621825, 0x24020001, 
+0xaf830050, 0xaf820200, 0x1080001e, 0xaf820220, 
+0x3c020001, 0x8c423e14, 0x1440001a, 0x3c033f00, 
+0x3c020001, 0x8c423d70, 0x1000001a, 0x346300e0, 
+0x8f830050, 0x3c040001, 0x8c843ec8, 0x3442ffff, 
+0x621824, 0x1080000f, 0xaf830050, 0x3c020001, 
+0x8c423e14, 0x1440000b, 0x3c043f00, 0x3c030001, 
+0x8c633d70, 0x348400e0, 0x24020001, 0xaf820200, 
+0xaf820220, 0x641825, 0xaf830200, 0x10000008, 
+0x3c05f700, 0x3c020001, 0x8c423d70, 0x3c033f00, 
+0x346300e2, 0x431025, 0xaf820200, 0x3c05f700, 
+0x34a58000, 0x3c030001, 0x8c633d74, 0x3c020001, 
+0x8c423d80, 0x3c040001, 0x8c843d9c, 0x651825, 
+0x431025, 0x441025, 0xaf820220, 0x3e00008, 
+0x0, 0x3c030001, 0x8c633da0, 0x3c020001, 
+0x8c423da4, 0x10620003, 0x24020002, 0x3c010001, 
+0xac233da4, 0x1062001d, 0x2c620003, 0x10400025, 
+0x24020001, 0x14620023, 0x24020004, 0x3c030001, 
+0x8c633d88, 0x10620006, 0x24020008, 0x1462000c, 
+0x3c0200c8, 0x344201fb, 0x10000009, 0xaf820238, 
+0x24020e01, 0xaf820238, 0x8f820044, 0x3c03ffff, 
+0x34633f7f, 0x431024, 0x34420080, 0xaf820044, 
+0x8f830054, 0x24020002, 0x3c010001, 0xac223da0, 
+0x3c010001, 0x1000000b, 0xac233ed4, 0x8f830054, 
+0x3c020001, 0x8c423ed4, 0x2463d8f0, 0x431023, 
+0x2c422710, 0x14400003, 0x24020009, 0x3c010001, 
+0xac223da0, 0x3e00008, 0x0, 0x27bdffd8, 
 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 
 0xafb10014, 0xc08821, 0xafb00010, 0x8021, 
-0xafbf0020, 0xa6200000, 0xc0045f7, 0x24040001, 
+0xafbf0020, 0xa6200000, 0xc004523, 0x24040001, 
 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc0045f7, 0x2021, 0xc0045f7, 0x24040001, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x2021, 0xc004523, 0x24040001, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x24100010, 0x2501024, 0x10400002, 0x2021, 
-0x24040001, 0xc0045f7, 0x108042, 0x1600fffa, 
+0x24040001, 0xc004523, 0x108042, 0x1600fffa, 
 0x2501024, 0x24100010, 0x2701024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fffa, 0x2701024, 0xc00461d, 0x34108000, 
-0xc00461d, 0x0, 0xc0045d7, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fffa, 0x2701024, 0xc004549, 0x34108000, 
+0xc004549, 0x0, 0xc004503, 0x0, 
 0x50400005, 0x108042, 0x96220000, 0x501025, 
 0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc00461d, 0x0, 0x8fbf0020, 0x8fb3001c, 
+0xc004549, 0x0, 0x8fbf0020, 0x8fb3001c, 
 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 
 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 
 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, 
-0xafb00010, 0x8021, 0xafbf0020, 0xc0045f7, 
+0xafb00010, 0x8021, 0xafbf0020, 0xc004523, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc0045f7, 0x2021, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 
+0x0, 0xc004523, 0x2021, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0xc004523, 
 0x24040001, 0x24100010, 0x2301024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
-0x108042, 0x1600fffa, 0x2501024, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
+0x108042, 0x1600fffa, 0x2501024, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0x34108000, 
 0x96620000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, 
-0x0, 0xc00461d, 0x0, 0x8fbf0020, 
+0x24040001, 0xc004523, 0x108042, 0x1600fff8, 
+0x0, 0xc004549, 0x0, 0x8fbf0020, 
 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633e50, 
-0x3c020001, 0x8c423e94, 0x27bdffd8, 0xafbf0020, 
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c633db0, 
+0x3c020001, 0x8c423df4, 0x27bdffd8, 0xafbf0020, 
 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, 
-0xac233e94, 0x2463ffff, 0x2c620013, 0x10400349, 
-0x31080, 0x3c010001, 0x220821, 0x8c223c80, 
-0x400008, 0x0, 0xc00461d, 0x8021, 
-0x34028000, 0xa7a20010, 0x27b10010, 0xc0045f7, 
+0xac233df4, 0x2463ffff, 0x2c620013, 0x10400349, 
+0x31080, 0x3c010001, 0x220821, 0x8c223be0, 
+0x400008, 0x0, 0xc004549, 0x8021, 
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004523, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc0045f7, 0x2021, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 
+0x0, 0xc004523, 0x2021, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0xc004523, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0xc0045f7, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0xc004523, 
 0x2021, 0x108042, 0x1600fffc, 0x0, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fff8, 0x0, 0xc00461d, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fff8, 0x0, 0xc004549, 0x0, 
 0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, 
-0x8021, 0xc0045f7, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc0045f7, 
-0x2021, 0xc0045f7, 0x24040001, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0x24100010, 
+0x8021, 0xc004523, 0x24040001, 0x26100001, 
+0x2e020020, 0x1440fffb, 0x0, 0xc004523, 
+0x2021, 0xc004523, 0x24040001, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0x24100010, 
 0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020001, 
-0x24100010, 0xc0045f7, 0x2021, 0x108042, 
-0x1600fffc, 0x0, 0xc00461d, 0x34108000, 
-0xc00461d, 0x0, 0xc0045d7, 0x0, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020001, 
+0x24100010, 0xc004523, 0x2021, 0x108042, 
+0x1600fffc, 0x0, 0xc004549, 0x34108000, 
+0xc004549, 0x0, 0xc004503, 0x0, 
 0x50400005, 0x108042, 0x96220000, 0x501025, 
 0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc00461d, 0x0, 0x97a20010, 0x30428000, 
+0xc004549, 0x0, 0x97a20010, 0x30428000, 
 0x144002dc, 0x24020003, 0x100002d8, 0x0, 
 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
-0xc0045f7, 0x2021, 0x108042, 0x1600fffc, 
-0x0, 0xc0045f7, 0x24040001, 0xc0045f7, 
+0xc004523, 0x2021, 0x108042, 0x1600fffc, 
+0x0, 0xc004523, 0x24040001, 0xc004523, 
 0x2021, 0x34108000, 0x96220000, 0x501024, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
-0x108042, 0x1600fff8, 0x0, 0xc00461d, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
+0x108042, 0x1600fff8, 0x0, 0xc004549, 
 0x0, 0x8f830054, 0x10000296, 0x24020004, 
-0x8f830054, 0x3c020001, 0x8c423f7c, 0x2463ff9c, 
+0x8f830054, 0x3c020001, 0x8c423edc, 0x2463ff9c, 
 0x431023, 0x2c420064, 0x1440029e, 0x24020002, 
-0x3c030001, 0x8c633f80, 0x10620297, 0x2c620003, 
+0x3c030001, 0x8c633ee0, 0x10620297, 0x2c620003, 
 0x14400296, 0x24020011, 0x24020003, 0x10620005, 
 0x24020004, 0x10620291, 0x2402000f, 0x1000028f, 
 0x24020011, 0x1000028d, 0x24020005, 0x24020014, 
-0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, 
+0xa7a20010, 0x27b10010, 0x8021, 0xc004523, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc0045f7, 0x2021, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 
+0x0, 0xc004523, 0x2021, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0xc004523, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
-0x108042, 0x1600fffa, 0x32020012, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
+0x108042, 0x1600fffa, 0x32020012, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0x34108000, 
 0x96220000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, 
-0x0, 0xc00461d, 0x0, 0x8f830054, 
+0x24040001, 0xc004523, 0x108042, 0x1600fff8, 
+0x0, 0xc004549, 0x0, 0x8f830054, 
 0x10000248, 0x24020006, 0x8f830054, 0x3c020001, 
-0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 
+0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 
 0x14400250, 0x24020007, 0x1000024c, 0x0, 
 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020013, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020013, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020013, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fff8, 0x0, 0xc00461d, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fff8, 0x0, 0xc004549, 0x0, 
 0x8f830054, 0x10000207, 0x24020008, 0x8f830054, 
-0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, 
-0xc0045f7, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x24040001, 
+0xc004523, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, 
-0xc00461d, 0x34108000, 0xc00461d, 0x0, 
-0xc0045d7, 0x0, 0x50400005, 0x108042, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004549, 0x34108000, 0xc004549, 0x0, 
+0xc004503, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc00461d, 0x8021, 
+0x1600fff7, 0x0, 0xc004549, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fff8, 0x0, 0xc00461d, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fff8, 0x0, 0xc004549, 0x0, 
 0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, 
-0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, 
-0xc0045f7, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x24040001, 
+0xc004523, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020017, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, 
-0xc00461d, 0x34108000, 0xc00461d, 0x0, 
-0xc0045d7, 0x0, 0x50400005, 0x108042, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020017, 
+0xc004549, 0x34108000, 0xc004549, 0x0, 
+0xc004503, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc00461d, 0x8021, 
+0x1600fff7, 0x0, 0xc004549, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020017, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020017, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020017, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fff8, 0x0, 0xc00461d, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fff8, 0x0, 0xc004549, 0x0, 
 0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, 
-0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x14400127, 0x24020012, 0x10000123, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, 
-0xc0045f7, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x24040001, 
+0xc004523, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020014, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, 
-0xc00461d, 0x34108000, 0xc00461d, 0x0, 
-0xc0045d7, 0x0, 0x50400005, 0x108042, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020014, 
+0xc004549, 0x34108000, 0xc004549, 0x0, 
+0xc004503, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc00461d, 0x8021, 
+0x1600fff7, 0x0, 0xc004549, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020014, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020014, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020014, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fff8, 0x0, 0xc00461d, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fff8, 0x0, 0xc004549, 0x0, 
 0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, 
-0x3c020001, 0x8c423f7c, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c423edc, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x24040001, 
-0xc0045f7, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x24040001, 
+0xc004523, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, 
-0xc00461d, 0x34108000, 0xc00461d, 0x0, 
-0xc0045d7, 0x0, 0x50400005, 0x108042, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004549, 0x34108000, 0xc004549, 0x0, 
+0xc004503, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc00461d, 0x8021, 
+0x1600fff7, 0x0, 0xc004549, 0x8021, 
 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, 
-0xc0045f7, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
-0xc0045f7, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
+0xc004523, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
+0xc004523, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc0045f7, 0x108042, 0x1600fffa, 0x32020018, 
-0xc0045f7, 0x24040001, 0xc0045f7, 0x2021, 
+0xc004523, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004523, 0x24040001, 0xc004523, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
-0x1600fff8, 0x0, 0xc00461d, 0x0, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
+0x1600fff8, 0x0, 0xc004549, 0x0, 
 0x8f830054, 0x10000037, 0x2402000e, 0x24020840, 
-0xa7a20010, 0x27b10010, 0x8021, 0xc0045f7, 
+0xa7a20010, 0x27b10010, 0x8021, 0xc004523, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc0045f7, 0x2021, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0xc0045f7, 
+0x0, 0xc004523, 0x2021, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0xc004523, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc0045f7, 0x108042, 
+0x2021, 0x24040001, 0xc004523, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 
-0x10400002, 0x2021, 0x24040001, 0xc0045f7, 
-0x108042, 0x1600fffa, 0x32020013, 0xc0045f7, 
-0x24040001, 0xc0045f7, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004523, 
+0x108042, 0x1600fffa, 0x32020013, 0xc004523, 
+0x24040001, 0xc004523, 0x2021, 0x34108000, 
 0x96220000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc0045f7, 0x108042, 0x1600fff8, 
-0x0, 0xc00461d, 0x0, 0x8f830054, 
-0x24020010, 0x3c010001, 0xac223e50, 0x3c010001, 
-0x1000000c, 0xac233f7c, 0x8f830054, 0x3c020001, 
-0x8c423f7c, 0x2463ff9c, 0x431023, 0x2c420064, 
+0x24040001, 0xc004523, 0x108042, 0x1600fff8, 
+0x0, 0xc004549, 0x0, 0x8f830054, 
+0x24020010, 0x3c010001, 0xac223db0, 0x3c010001, 
+0x1000000c, 0xac233edc, 0x8f830054, 0x3c020001, 
+0x8c423edc, 0x2463ff9c, 0x431023, 0x2c420064, 
 0x14400004, 0x0, 0x24020011, 0x3c010001, 
-0xac223e50, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
+0xac223db0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 
 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 
 0x8f840054, 0x8f820054, 0xa32824, 0x10000002, 
@@ -7942,136 +7899,136 @@
 0x621023, 0x2c420002, 0x1440fffc, 0x0, 
 0x3e00008, 0x0, 0x0, 0x27bdffe8, 
 0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, 
-0x0, 0x3c020001, 0x8c423f68, 0x14400005, 
-0x0, 0xc003be0, 0x8f840224, 0x100001d8, 
+0x0, 0x3c020001, 0x8c423ec8, 0x14400005, 
+0x0, 0xc003b0b, 0x8f840224, 0x100001d8, 
 0x0, 0x8f820220, 0x3c030008, 0x431024, 
 0x10400026, 0x24020001, 0x8f840224, 0x8f820220, 
 0x3c030400, 0x431024, 0x10400006, 0x0, 
-0x3c010001, 0xac205fe0, 0x3c010001, 0x1000000b, 
-0xac206000, 0x3c030001, 0x24635fe0, 0x8c620000, 
+0x3c010001, 0xac205f40, 0x3c010001, 0x1000000b, 
+0xac205f60, 0x3c030001, 0x24635f40, 0x8c620000, 
 0x24420001, 0xac620000, 0x2c420002, 0x14400003, 
-0x24020001, 0x3c010001, 0xac226000, 0x3c020001, 
-0x8c426000, 0x10400006, 0x30820040, 0x10400004, 
-0x24020001, 0x3c010001, 0x10000003, 0xac226004, 
-0x3c010001, 0xac206004, 0x3c010001, 0xac245fdc, 
-0x3c010001, 0x1000000b, 0xac206010, 0x3c010001, 
-0xac226010, 0x3c010001, 0xac206000, 0x3c010001, 
-0xac205fe0, 0x3c010001, 0xac206004, 0x3c010001, 
-0xac205fdc, 0x3c030001, 0x8c635fd0, 0x3c020001, 
-0x8c425fd4, 0x50620004, 0x2463ffff, 0x3c010001, 
-0xac235fd4, 0x2463ffff, 0x2c62000e, 0x10400194, 
-0x31080, 0x3c010001, 0x220821, 0x8c223cd0, 
+0x24020001, 0x3c010001, 0xac225f60, 0x3c020001, 
+0x8c425f60, 0x10400006, 0x30820040, 0x10400004, 
+0x24020001, 0x3c010001, 0x10000003, 0xac225f64, 
+0x3c010001, 0xac205f64, 0x3c010001, 0xac245f3c, 
+0x3c010001, 0x1000000b, 0xac205f70, 0x3c010001, 
+0xac225f70, 0x3c010001, 0xac205f60, 0x3c010001, 
+0xac205f40, 0x3c010001, 0xac205f64, 0x3c010001, 
+0xac205f3c, 0x3c030001, 0x8c635f30, 0x3c020001, 
+0x8c425f34, 0x50620004, 0x2463ffff, 0x3c010001, 
+0xac235f34, 0x2463ffff, 0x2c62000e, 0x10400194, 
+0x31080, 0x3c010001, 0x220821, 0x8c223c30, 
 0x400008, 0x0, 0x24020002, 0x3c010001, 
-0xac206000, 0x3c010001, 0xac205fe0, 0x3c010001, 
-0xac205fdc, 0x3c010001, 0xac206004, 0x3c010001, 
-0xac205ff8, 0x3c010001, 0xac205ff0, 0xaf800224, 
-0x3c010001, 0xac225fd0, 0x3c020001, 0x8c426010, 
-0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003be0, 
+0xac205f60, 0x3c010001, 0xac205f40, 0x3c010001, 
+0xac205f3c, 0x3c010001, 0xac205f64, 0x3c010001, 
+0xac205f58, 0x3c010001, 0xac205f50, 0xaf800224, 
+0x3c010001, 0xac225f30, 0x3c020001, 0x8c425f70, 
+0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003b0b, 
 0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, 
-0x431024, 0xaf820200, 0x3c010001, 0xac206020, 
-0x8f830054, 0x3c020001, 0x8c425ff8, 0x24040001, 
-0x3c010001, 0xac24600c, 0x24420001, 0x3c010001, 
-0xac225ff8, 0x2c420004, 0x3c010001, 0xac235ff4, 
-0x14400006, 0x24020003, 0x3c010001, 0xac243e2c, 
-0x3c010001, 0x1000015e, 0xac205ff8, 0x3c010001, 
-0x1000015b, 0xac225fd0, 0x8f830054, 0x3c020001, 
-0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400003, 0x24020004, 0x3c010001, 0xac225fd0, 
-0x3c020001, 0x8c426010, 0x14400021, 0x3c02fdff, 
+0x431024, 0xaf820200, 0x3c010001, 0xac205f80, 
+0x8f830054, 0x3c020001, 0x8c425f58, 0x24040001, 
+0x3c010001, 0xac245f6c, 0x24420001, 0x3c010001, 
+0xac225f58, 0x2c420004, 0x3c010001, 0xac235f54, 
+0x14400006, 0x24020003, 0x3c010001, 0xac243d8c, 
+0x3c010001, 0x1000015e, 0xac205f58, 0x3c010001, 
+0x1000015b, 0xac225f30, 0x8f830054, 0x3c020001, 
+0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710, 
+0x14400003, 0x24020004, 0x3c010001, 0xac225f30, 
+0x3c020001, 0x8c425f70, 0x14400021, 0x3c02fdff, 
 0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, 
-0x8c843f6c, 0x3c010001, 0xc004828, 0xac205fe8, 
-0x3c020001, 0x8c42601c, 0xaf820204, 0x3c020001, 
-0x8c426010, 0x14400012, 0x3c03fdff, 0x8f820204, 
+0x8c843ecc, 0x3c010001, 0xc004754, 0xac205f48, 
+0x3c020001, 0x8c425f7c, 0xaf820204, 0x3c020001, 
+0x8c425f70, 0x14400012, 0x3c03fdff, 0x8f820204, 
 0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, 
-0x3c030001, 0x8c63601c, 0x24020005, 0x3c010001, 
-0xac225fd0, 0x3c010001, 0x10000131, 0xac236020, 
-0x3c020001, 0x8c426010, 0x10400010, 0x3c02fdff, 
-0x3c020001, 0x8c423eac, 0x24420001, 0x3c010001, 
-0xac223eac, 0x2c420002, 0x14400125, 0x24020001, 
-0x3c010001, 0xac223eb4, 0x3c010001, 0xac203eac, 
-0x3c010001, 0x1000011e, 0xac223e2c, 0x3c030001, 
-0x8c636000, 0x3442ffff, 0x10600119, 0x282a024, 
-0x3c020001, 0x8c425fdc, 0x10400115, 0x0, 
-0x3c010001, 0xac226008, 0x24020003, 0x3c010001, 
-0xac225fe0, 0x100000b8, 0x24020006, 0x3c010001, 
-0xac205fe8, 0x8f820204, 0x34420040, 0xaf820204, 
-0x3c020001, 0x8c426020, 0x24030007, 0x3c010001, 
-0xac235fd0, 0x34420040, 0x3c010001, 0xac226020, 
-0x3c020001, 0x8c426000, 0x10400005, 0x0, 
-0x3c020001, 0x8c425fdc, 0x104000f0, 0x24020002, 
-0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, 
-0x104000ea, 0x24020002, 0x3c020001, 0x8c426004, 
-0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425fdc, 
-0x3c030001, 0x8c636008, 0x441024, 0x641824, 
+0x3c030001, 0x8c635f7c, 0x24020005, 0x3c010001, 
+0xac225f30, 0x3c010001, 0x10000131, 0xac235f80, 
+0x3c020001, 0x8c425f70, 0x10400010, 0x3c02fdff, 
+0x3c020001, 0x8c423e0c, 0x24420001, 0x3c010001, 
+0xac223e0c, 0x2c420002, 0x14400125, 0x24020001, 
+0x3c010001, 0xac223e14, 0x3c010001, 0xac203e0c, 
+0x3c010001, 0x1000011e, 0xac223d8c, 0x3c030001, 
+0x8c635f60, 0x3442ffff, 0x10600119, 0x282a024, 
+0x3c020001, 0x8c425f3c, 0x10400115, 0x0, 
+0x3c010001, 0xac225f68, 0x24020003, 0x3c010001, 
+0xac225f40, 0x100000b8, 0x24020006, 0x3c010001, 
+0xac205f48, 0x8f820204, 0x34420040, 0xaf820204, 
+0x3c020001, 0x8c425f80, 0x24030007, 0x3c010001, 
+0xac235f30, 0x34420040, 0x3c010001, 0xac225f80, 
+0x3c020001, 0x8c425f60, 0x10400005, 0x0, 
+0x3c020001, 0x8c425f3c, 0x104000f0, 0x24020002, 
+0x3c050001, 0x24a55f40, 0x8ca20000, 0x2c424e21, 
+0x104000ea, 0x24020002, 0x3c020001, 0x8c425f64, 
+0x104000ef, 0x2404ffbf, 0x3c020001, 0x8c425f3c, 
+0x3c030001, 0x8c635f68, 0x441024, 0x641824, 
 0x10430004, 0x24020001, 0x3c010001, 0x100000e4, 
-0xac225fd0, 0x24020003, 0xaca20000, 0x24020008, 
-0x3c010001, 0xac225fd0, 0x3c020001, 0x8c42600c, 
-0x1040000c, 0x24020001, 0x3c040001, 0xc004835, 
-0x8c845fdc, 0x3c020001, 0x8c426028, 0x14400005, 
-0x24020001, 0x3c020001, 0x8c426024, 0x10400006, 
-0x24020001, 0x3c010001, 0xac223e2c, 0x3c010001, 
-0x100000cb, 0xac205ff8, 0x3c020001, 0x8c425ff0, 
-0x3c030001, 0x8c635fdc, 0x2c420001, 0x210c0, 
-0x30630008, 0x3c010001, 0xac225ff0, 0x3c010001, 
-0xac235fec, 0x8f830054, 0x24020009, 0x3c010001, 
-0xac225fd0, 0x3c010001, 0x100000b9, 0xac235ff4, 
-0x8f830054, 0x3c020001, 0x8c425ff4, 0x2463d8f0, 
+0xac225f30, 0x24020003, 0xaca20000, 0x24020008, 
+0x3c010001, 0xac225f30, 0x3c020001, 0x8c425f6c, 
+0x1040000c, 0x24020001, 0x3c040001, 0xc004761, 
+0x8c845f3c, 0x3c020001, 0x8c425f88, 0x14400005, 
+0x24020001, 0x3c020001, 0x8c425f84, 0x10400006, 
+0x24020001, 0x3c010001, 0xac223d8c, 0x3c010001, 
+0x100000cb, 0xac205f58, 0x3c020001, 0x8c425f50, 
+0x3c030001, 0x8c635f3c, 0x2c420001, 0x210c0, 
+0x30630008, 0x3c010001, 0xac225f50, 0x3c010001, 
+0xac235f4c, 0x8f830054, 0x24020009, 0x3c010001, 
+0xac225f30, 0x3c010001, 0x100000b9, 0xac235f54, 
+0x8f830054, 0x3c020001, 0x8c425f54, 0x2463d8f0, 
 0x431023, 0x2c422710, 0x1440009f, 0x0, 
-0x3c020001, 0x8c426000, 0x10400005, 0x0, 
-0x3c020001, 0x8c425fdc, 0x104000a0, 0x24020002, 
-0x3c030001, 0x24635fe0, 0x8c620000, 0x2c424e21, 
-0x1040009a, 0x24020002, 0x3c020001, 0x8c42600c, 
-0x1040000e, 0x0, 0x3c020001, 0x8c425fdc, 
-0x3c010001, 0xac20600c, 0x30420080, 0x1040002f, 
+0x3c020001, 0x8c425f60, 0x10400005, 0x0, 
+0x3c020001, 0x8c425f3c, 0x104000a0, 0x24020002, 
+0x3c030001, 0x24635f40, 0x8c620000, 0x2c424e21, 
+0x1040009a, 0x24020002, 0x3c020001, 0x8c425f6c, 
+0x1040000e, 0x0, 0x3c020001, 0x8c425f3c, 
+0x3c010001, 0xac205f6c, 0x30420080, 0x1040002f, 
 0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, 
 0x24020003, 0x10000029, 0x2402000c, 0x3c020001, 
-0x8c425fdc, 0x30420080, 0x14400005, 0x24020003, 
+0x8c425f3c, 0x30420080, 0x14400005, 0x24020003, 
 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, 
-0xac620000, 0x2402000a, 0x3c010001, 0xac225fd0, 
-0x3c040001, 0x24846018, 0x8c820000, 0x3c030001, 
-0x8c635ff0, 0x431025, 0xaf820204, 0x8c830000, 
-0x3c040001, 0x8c845ff0, 0x2402000b, 0x3c010001, 
-0xac225fd0, 0x641825, 0x3c010001, 0xac236020, 
-0x3c050001, 0x24a55fe0, 0x8ca20000, 0x2c424e21, 
-0x10400066, 0x24020002, 0x3c020001, 0x8c426010, 
+0xac620000, 0x2402000a, 0x3c010001, 0xac225f30, 
+0x3c040001, 0x24845f78, 0x8c820000, 0x3c030001, 
+0x8c635f50, 0x431025, 0xaf820204, 0x8c830000, 
+0x3c040001, 0x8c845f50, 0x2402000b, 0x3c010001, 
+0xac225f30, 0x641825, 0x3c010001, 0xac235f80, 
+0x3c050001, 0x24a55f40, 0x8ca20000, 0x2c424e21, 
+0x10400066, 0x24020002, 0x3c020001, 0x8c425f70, 
 0x10400005, 0x0, 0x2402000c, 0x3c010001, 
-0x10000067, 0xac225fd0, 0x3c020001, 0x8c426000, 
-0x10400063, 0x0, 0x3c040001, 0x8c845fdc, 
-0x10800055, 0x30820008, 0x3c030001, 0x8c635fec, 
-0x1062005b, 0x24020003, 0x3c010001, 0xac246008, 
+0x10000067, 0xac225f30, 0x3c020001, 0x8c425f60, 
+0x10400063, 0x0, 0x3c040001, 0x8c845f3c, 
+0x10800055, 0x30820008, 0x3c030001, 0x8c635f4c, 
+0x1062005b, 0x24020003, 0x3c010001, 0xac245f68, 
 0xaca20000, 0x24020006, 0x3c010001, 0x10000054, 
-0xac225fd0, 0x8f820200, 0x34420002, 0xaf820200, 
-0x8f830054, 0x2402000d, 0x3c010001, 0xac225fd0, 
-0x3c010001, 0xac235ff4, 0x8f830054, 0x3c020001, 
-0x8c425ff4, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400031, 0x0, 0x3c020001, 0x8c426010, 
-0x10400020, 0x2402000e, 0x3c030001, 0x8c636024, 
-0x3c010001, 0x14600015, 0xac225fd0, 0xc003c9e, 
-0x0, 0x3c050001, 0x8ca53e28, 0xc0049b1, 
-0x2021, 0x3c030001, 0x8c633e28, 0x24020004, 
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c423e24, 
-0x10000003, 0x2403fff7, 0x3c020001, 0x8c423e24, 
-0x431024, 0x3c010001, 0xac223e24, 0x8f830224, 
-0x3c020200, 0x3c010001, 0xac23602c, 0x10000020, 
-0x282a025, 0x3c020001, 0x8c426000, 0x10400005, 
-0x0, 0x3c020001, 0x8c425fdc, 0x1040000f, 
-0x24020002, 0x3c020001, 0x8c425fe0, 0x2c424e21, 
-0x1040000a, 0x24020002, 0x3c020001, 0x8c426000, 
-0x1040000f, 0x0, 0x3c020001, 0x8c425fdc, 
+0xac225f30, 0x8f820200, 0x34420002, 0xaf820200, 
+0x8f830054, 0x2402000d, 0x3c010001, 0xac225f30, 
+0x3c010001, 0xac235f54, 0x8f830054, 0x3c020001, 
+0x8c425f54, 0x2463d8f0, 0x431023, 0x2c422710, 
+0x14400031, 0x0, 0x3c020001, 0x8c425f70, 
+0x10400020, 0x2402000e, 0x3c030001, 0x8c635f84, 
+0x3c010001, 0x14600015, 0xac225f30, 0xc003bc9, 
+0x0, 0x3c050001, 0x8ca53d88, 0xc0048dd, 
+0x2021, 0x3c030001, 0x8c633d88, 0x24020004, 
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c423d84, 
+0x10000003, 0x2403fff7, 0x3c020001, 0x8c423d84, 
+0x431024, 0x3c010001, 0xac223d84, 0x8f830224, 
+0x3c020200, 0x3c010001, 0xac235f8c, 0x10000020, 
+0x282a025, 0x3c020001, 0x8c425f60, 0x10400005, 
+0x0, 0x3c020001, 0x8c425f3c, 0x1040000f, 
+0x24020002, 0x3c020001, 0x8c425f40, 0x2c424e21, 
+0x1040000a, 0x24020002, 0x3c020001, 0x8c425f60, 
+0x1040000f, 0x0, 0x3c020001, 0x8c425f3c, 
 0x1440000b, 0x0, 0x24020002, 0x3c010001, 
-0x10000007, 0xac225fd0, 0x3c020001, 0x8c426000, 
-0x10400003, 0x0, 0xc003be0, 0x0, 
+0x10000007, 0xac225f30, 0x3c020001, 0x8c425f60, 
+0x10400003, 0x0, 0xc003b0b, 0x0, 
 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 
 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030001, 
-0x24636028, 0x8c620000, 0x10400005, 0x34422000, 
-0x3c010001, 0xac22601c, 0x10000003, 0xac600000, 
-0x3c010001, 0xac24601c, 0x3e00008, 0x0, 
+0x24635f88, 0x8c620000, 0x10400005, 0x34422000, 
+0x3c010001, 0xac225f7c, 0x10000003, 0xac600000, 
+0x3c010001, 0xac245f7c, 0x3e00008, 0x0, 
 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010001, 
-0xac226024, 0x14400067, 0x3c02ffff, 0x34421f0e, 
+0xac225f84, 0x14400067, 0x3c02ffff, 0x34421f0e, 
 0x821024, 0x14400061, 0x24020030, 0x30822000, 
 0x1040005d, 0x30838000, 0x31a02, 0x30820001, 
-0x21200, 0x3c040001, 0x8c843f6c, 0x621825, 
-0x331c2, 0x3c030001, 0x24633eb8, 0x30828000, 
+0x21200, 0x3c040001, 0x8c843ecc, 0x621825, 
+0x331c2, 0x3c030001, 0x24633e18, 0x30828000, 
 0x21202, 0x30840001, 0x42200, 0x441025, 
 0x239c2, 0x61080, 0x431021, 0x471021, 
 0x90430000, 0x24020001, 0x10620025, 0x0, 
@@ -8079,86 +8036,86 @@
 0x1062002c, 0x3c05000f, 0x10000037, 0x0, 
 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 
 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 
-0xaf820220, 0x3c010001, 0xac206044, 0x3c010001, 
-0x10000034, 0xac20604c, 0x8f820200, 0x34420100, 
+0xaf820220, 0x3c010001, 0xac205fa4, 0x3c010001, 
+0x10000034, 0xac205fac, 0x8f820200, 0x34420100, 
 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 
 0x431024, 0xaf820220, 0x24020100, 0x3c010001, 
-0xac226044, 0x3c010001, 0x10000026, 0xac20604c, 
+0xac225fa4, 0x3c010001, 0x10000026, 0xac205fac, 
 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 
 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, 
-0x3c010001, 0xac206044, 0x3c010001, 0x10000019, 
-0xac23604c, 0x8f820200, 0x34420100, 0xaf820200, 
+0x3c010001, 0xac205fa4, 0x3c010001, 0x10000019, 
+0xac235fac, 0x8f820200, 0x34420100, 0xaf820200, 
 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, 
-0x24020100, 0x3c010001, 0xac226044, 0x3c010001, 
-0x1000000c, 0xac23604c, 0x34a5ffff, 0x3c040001, 
-0x24843d08, 0xafa30010, 0xc002a03, 0xafa00014, 
+0x24020100, 0x3c010001, 0xac225fa4, 0x3c010001, 
+0x1000000c, 0xac235fac, 0x34a5ffff, 0x3c040001, 
+0x24843c68, 0xafa30010, 0xc0029bb, 0xafa00014, 
 0x10000004, 0x0, 0x24020030, 0x3c010001, 
-0xac226028, 0x8fbf0018, 0x3e00008, 0x27bd0020, 
+0xac225f88, 0x8fbf0018, 0x3e00008, 0x27bd0020, 
 0x0, 0x0, 0x0, 0x27bdffc8, 
 0xafb10024, 0x808821, 0xafb3002c, 0xa09821, 
-0xafb00020, 0xc08021, 0x3c040001, 0x24843d20, 
-0x3c050009, 0x3c020001, 0x8c423e28, 0x34a59001, 
+0xafb00020, 0xc08021, 0x3c040001, 0x24843c80, 
+0x3c050009, 0x3c020001, 0x8c423d88, 0x34a59001, 
 0x2203021, 0x2603821, 0xafbf0030, 0xafb20028, 
-0xa7a0001a, 0xafb00014, 0xc002a03, 0xafa20010, 
+0xa7a0001a, 0xafb00014, 0xc0029bb, 0xafa20010, 
 0x24020002, 0x126200eb, 0x2e620003, 0x10400005, 
 0x24020001, 0x1262000a, 0x3c02fffb, 0x100000e5, 
 0x0, 0x24020004, 0x1262006d, 0x24020008, 
 0x1262006c, 0x3c02ffec, 0x100000de, 0x0, 
 0x3442ffff, 0x2028024, 0x119140, 0x3c010001, 
-0x320821, 0xac30603c, 0x3c024000, 0x2021024, 
+0x320821, 0xac305f9c, 0x3c024000, 0x2021024, 
 0x10400046, 0x1023c2, 0x30840030, 0x101382, 
-0x3042000c, 0x3c030001, 0x24633e54, 0x431021, 
+0x3042000c, 0x3c030001, 0x24633db4, 0x431021, 
 0x823821, 0x3c020020, 0x2021024, 0x10400006, 
-0x24020100, 0x3c010001, 0x320821, 0xac226040, 
+0x24020100, 0x3c010001, 0x320821, 0xac225fa0, 
 0x10000005, 0x3c020080, 0x3c010001, 0x320821, 
-0xac206040, 0x3c020080, 0x2021024, 0x10400006, 
+0xac205fa0, 0x3c020080, 0x2021024, 0x10400006, 
 0x111940, 0x3c020001, 0x3c010001, 0x230821, 
-0x10000005, 0xac226048, 0x111140, 0x3c010001, 
-0x220821, 0xac206048, 0x94e30000, 0x32024000, 
+0x10000005, 0xac225fa8, 0x111140, 0x3c010001, 
+0x220821, 0xac205fa8, 0x94e30000, 0x32024000, 
 0x10400003, 0xa7a30018, 0x34624000, 0xa7a20018, 
 0x24040001, 0x94e20002, 0x24050004, 0x24e60002, 
-0x34420001, 0xc00423a, 0xa4e20002, 0x24040001, 
-0x2821, 0xc00423a, 0x27a60018, 0x3c020001, 
-0x8c423e28, 0x24110001, 0x3c010001, 0xac313e34, 
-0x14530004, 0x32028000, 0xc003be0, 0x0, 
-0x32028000, 0x10400097, 0x0, 0xc003be0, 
-0x0, 0x24020002, 0x3c010001, 0xac313e2c, 
-0x3c010001, 0x1000008f, 0xac223e28, 0x24040001, 
-0x24050004, 0x27b0001a, 0xc00423a, 0x2003021, 
-0x24040001, 0x2821, 0xc00423a, 0x2003021, 
-0x3c020001, 0x521021, 0x8c426034, 0x3c040001, 
-0x8c843e28, 0x3c03bfff, 0x3463ffff, 0x3c010001, 
-0xac333e34, 0x431024, 0x3c010001, 0x320821, 
-0x10930076, 0xac226034, 0x10000076, 0x0, 
+0x34420001, 0xc004166, 0xa4e20002, 0x24040001, 
+0x2821, 0xc004166, 0x27a60018, 0x3c020001, 
+0x8c423d88, 0x24110001, 0x3c010001, 0xac313d94, 
+0x14530004, 0x32028000, 0xc003b0b, 0x0, 
+0x32028000, 0x10400097, 0x0, 0xc003b0b, 
+0x0, 0x24020002, 0x3c010001, 0xac313d8c, 
+0x3c010001, 0x1000008f, 0xac223d88, 0x24040001, 
+0x24050004, 0x27b0001a, 0xc004166, 0x2003021, 
+0x24040001, 0x2821, 0xc004166, 0x2003021, 
+0x3c020001, 0x521021, 0x8c425f94, 0x3c040001, 
+0x8c843d88, 0x3c03bfff, 0x3463ffff, 0x3c010001, 
+0xac333d94, 0x431024, 0x3c010001, 0x320821, 
+0x10930076, 0xac225f94, 0x10000076, 0x0, 
 0x3c02ffec, 0x3442ffff, 0x2028024, 0x3c020008, 
 0x2028025, 0x111140, 0x3c010001, 0x220821, 
-0xac306038, 0x3c022000, 0x2021024, 0x10400009, 
-0x0, 0x3c020001, 0x8c423eb4, 0x14400005, 
-0x24020001, 0x3c010001, 0xac223f68, 0x10000004, 
-0x3c024000, 0x3c010001, 0xac203f68, 0x3c024000, 
+0xac305f98, 0x3c022000, 0x2021024, 0x10400009, 
+0x0, 0x3c020001, 0x8c423e14, 0x14400005, 
+0x24020001, 0x3c010001, 0xac223ec8, 0x10000004, 
+0x3c024000, 0x3c010001, 0xac203ec8, 0x3c024000, 
 0x2021024, 0x1440001a, 0x0, 0x3c020001, 
-0x8c423f68, 0x10400005, 0x24022020, 0x3c010001, 
-0xac223f6c, 0x24020001, 0xaee204b8, 0x3c04bfff, 
-0x111940, 0x3c020001, 0x431021, 0x8c426030, 
-0x3c050001, 0x8ca53e28, 0x3484ffff, 0x441024, 
-0x3c010001, 0x230821, 0xac226030, 0x24020001, 
+0x8c423ec8, 0x10400005, 0x24022020, 0x3c010001, 
+0xac223ecc, 0x24020001, 0xaee204b8, 0x3c04bfff, 
+0x111940, 0x3c020001, 0x431021, 0x8c425f90, 
+0x3c050001, 0x8ca53d88, 0x3484ffff, 0x441024, 
+0x3c010001, 0x230821, 0xac225f90, 0x24020001, 
 0x10a20044, 0x0, 0x10000040, 0x0, 
-0x3c020001, 0x8c423f68, 0x1040001c, 0x24022000, 
-0x3c010001, 0xac223f6c, 0x3c0300a0, 0x2031024, 
+0x3c020001, 0x8c423ec8, 0x1040001c, 0x24022000, 
+0x3c010001, 0xac223ecc, 0x3c0300a0, 0x2031024, 
 0x14430005, 0x111140, 0x3402a000, 0x3c010001, 
-0x1000002d, 0xac223f6c, 0x3c030001, 0x621821, 
-0x8c636038, 0x3c020020, 0x621024, 0x10400004, 
-0x24022001, 0x3c010001, 0x10000023, 0xac223f6c, 
+0x1000002d, 0xac223ecc, 0x3c030001, 0x621821, 
+0x8c635f98, 0x3c020020, 0x621024, 0x10400004, 
+0x24022001, 0x3c010001, 0x10000023, 0xac223ecc, 
 0x3c020080, 0x621024, 0x1040001f, 0x3402a001, 
-0x3c010001, 0x1000001c, 0xac223f6c, 0x3c020020, 
+0x3c010001, 0x1000001c, 0xac223ecc, 0x3c020020, 
 0x2021024, 0x10400007, 0x111940, 0x24020100, 
-0x3c010001, 0x230821, 0xac226044, 0x10000006, 
+0x3c010001, 0x230821, 0xac225fa4, 0x10000006, 
 0x3c020080, 0x111140, 0x3c010001, 0x220821, 
-0xac206044, 0x3c020080, 0x2021024, 0x10400006, 
+0xac205fa4, 0x3c020080, 0x2021024, 0x10400006, 
 0x111940, 0x3c020001, 0x3c010001, 0x230821, 
-0x10000005, 0xac22604c, 0x111140, 0x3c010001, 
-0x220821, 0xac20604c, 0x3c030001, 0x8c633e28, 
-0x24020001, 0x10620003, 0x0, 0xc003be0, 
+0x10000005, 0xac225fac, 0x111140, 0x3c010001, 
+0x220821, 0xac205fac, 0x3c030001, 0x8c633d88, 
+0x24020001, 0x10620003, 0x0, 0xc003b0b, 
 0x0, 0x8fbf0030, 0x8fb3002c, 0x8fb20028, 
 0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0038, 
 0x27bdffd0, 0xafb50028, 0x80a821, 0xafb20020, 
@@ -8168,95 +8125,95 @@
 0x10400005, 0x24020001, 0x10a2000a, 0x158140, 
 0x100000ae, 0x2201021, 0x24020004, 0x10a2005e, 
 0x24020008, 0x10a2005d, 0x152940, 0x100000a7, 
-0x2201021, 0x3c030001, 0x701821, 0x8c63603c, 
+0x2201021, 0x3c030001, 0x701821, 0x8c635f9c, 
 0x3c024000, 0x621024, 0x14400009, 0x24040001, 
 0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, 
-0x300821, 0xac316034, 0x10000098, 0x2201021, 
-0x24050001, 0xc0041f8, 0x27a60010, 0x24040001, 
-0x24050001, 0xc0041f8, 0x27a60010, 0x97a20010, 
+0x300821, 0xac315f94, 0x10000098, 0x2201021, 
+0x24050001, 0xc004124, 0x27a60010, 0x24040001, 
+0x24050001, 0xc004124, 0x27a60010, 0x97a20010, 
 0x30420004, 0x10400034, 0x3c114000, 0x3c030001, 
-0x8c633f80, 0x24020003, 0x10620008, 0x2c620004, 
+0x8c633ee0, 0x24020003, 0x10620008, 0x2c620004, 
 0x14400029, 0x3c028000, 0x24020004, 0x10620014, 
 0x24040001, 0x10000024, 0x3c028000, 0x24040001, 
-0x24050011, 0x27b00012, 0xc0041f8, 0x2003021, 
-0x24040001, 0x24050011, 0xc0041f8, 0x2003021, 
+0x24050011, 0x27b00012, 0xc004124, 0x2003021, 
+0x24040001, 0x24050011, 0xc004124, 0x2003021, 
 0x97a30012, 0x30624000, 0x10400002, 0x3c130010, 
 0x3c130008, 0x3c120001, 0x10000010, 0x30628000, 
-0x24050014, 0x27b00012, 0xc0041f8, 0x2003021, 
-0x24040001, 0x24050014, 0xc0041f8, 0x2003021, 
+0x24050014, 0x27b00012, 0xc004124, 0x2003021, 
+0x24040001, 0x24050014, 0xc004124, 0x2003021, 
 0x97a30012, 0x30621000, 0x10400002, 0x3c130010, 
 0x3c130008, 0x3c120001, 0x30620800, 0x54400001, 
 0x3c120002, 0x3c028000, 0x2221025, 0x2531825, 
 0x10000007, 0x438825, 0x3c110001, 0x2308821, 
-0x8e31603c, 0x3c027fff, 0x3442ffff, 0x2228824, 
-0x151140, 0x3c010001, 0x220821, 0xac316034, 
+0x8e315f9c, 0x3c027fff, 0x3442ffff, 0x2228824, 
+0x151140, 0x3c010001, 0x220821, 0xac315f94, 
 0x1000004e, 0x2201021, 0x152940, 0x3c030001, 
-0x651821, 0x8c636038, 0x3c024000, 0x621024, 
+0x651821, 0x8c635f98, 0x3c024000, 0x621024, 
 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, 
-0x3c010001, 0x250821, 0xac316030, 0x1000003f, 
-0x2201021, 0x3c020001, 0x8c423e38, 0x10400033, 
-0x3c11c00c, 0x3c020001, 0x8c423eb4, 0x3c04c00c, 
-0x34842000, 0x3c030001, 0x8c633f68, 0x2102b, 
+0x3c010001, 0x250821, 0xac315f90, 0x1000003f, 
+0x2201021, 0x3c020001, 0x8c423d98, 0x10400033, 
+0x3c11c00c, 0x3c020001, 0x8c423e14, 0x3c04c00c, 
+0x34842000, 0x3c030001, 0x8c633ec8, 0x2102b, 
 0x21023, 0x441024, 0x10600003, 0x518825, 
 0x3c022000, 0x2228825, 0x3c020001, 0x451021, 
-0x8c426044, 0x10400003, 0x3c020020, 0x10000004, 
+0x8c425fa4, 0x10400003, 0x3c020020, 0x10000004, 
 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, 
-0x151140, 0x3c010001, 0x220821, 0x8c22604c, 
+0x151140, 0x3c010001, 0x220821, 0x8c225fac, 
 0x10400003, 0x3c020080, 0x10000004, 0x2228825, 
 0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, 
-0x8c423ea0, 0x10400002, 0x3c020800, 0x2228825, 
-0x3c020001, 0x8c423ea4, 0x10400002, 0x3c020400, 
-0x2228825, 0x3c020001, 0x8c423ea8, 0x10400006, 
+0x8c423e00, 0x10400002, 0x3c020800, 0x2228825, 
+0x3c020001, 0x8c423e04, 0x10400002, 0x3c020400, 
+0x2228825, 0x3c020001, 0x8c423e08, 0x10400006, 
 0x3c020100, 0x10000004, 0x2228825, 0x3c027fff, 
 0x3442ffff, 0x628824, 0x151140, 0x3c010001, 
-0x220821, 0xac316030, 0x2201021, 0x8fbf002c, 
+0x220821, 0xac315f90, 0x2201021, 0x8fbf002c, 
 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 
 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe0, 
 0xafb20018, 0x809021, 0xafbf001c, 0xafb10014, 
-0xafb00010, 0x8f840200, 0x3c030001, 0x8c633e28, 
+0xafb00010, 0x8f840200, 0x3c030001, 0x8c633d88, 
 0x8f860220, 0x24020002, 0x106200a6, 0x2c620003, 
 0x10400005, 0x24020001, 0x1062000a, 0x121940, 
 0x100000a0, 0x0, 0x24020004, 0x10620053, 
 0x24020008, 0x10620052, 0x128940, 0x10000099, 
-0x0, 0x3c050001, 0xa32821, 0x8ca5603c, 
-0x3c100001, 0x2038021, 0x8e106034, 0x3c024000, 
+0x0, 0x3c050001, 0xa32821, 0x8ca55f9c, 
+0x3c100001, 0x2038021, 0x8e105f94, 0x3c024000, 
 0xa21024, 0x10400038, 0x3c020008, 0x2021024, 
 0x10400020, 0x34840002, 0x3c020001, 0x431021, 
-0x8c426040, 0x10400005, 0x34840020, 0x34840100, 
+0x8c425fa0, 0x10400005, 0x34840020, 0x34840100, 
 0x3c020020, 0x10000006, 0x2028025, 0x2402feff, 
 0x822024, 0x3c02ffdf, 0x3442ffff, 0x2028024, 
-0x121140, 0x3c010001, 0x220821, 0x8c226048, 
+0x121140, 0x3c010001, 0x220821, 0x8c225fa8, 
 0x10400005, 0x3c020001, 0xc23025, 0x3c020080, 
 0x10000016, 0x2028025, 0x3c02fffe, 0x3442ffff, 
 0xc23024, 0x3c02ff7f, 0x3442ffff, 0x1000000f, 
 0x2028024, 0x2402fedf, 0x822024, 0x3c02fffe, 
 0x3442ffff, 0xc23024, 0x3c02ff5f, 0x3442ffff, 
-0x2028024, 0x3c010001, 0x230821, 0xac206040, 
-0x3c010001, 0x230821, 0xac206048, 0xaf840200, 
+0x2028024, 0x3c010001, 0x230821, 0xac205fa0, 
+0x3c010001, 0x230821, 0xac205fa8, 0xaf840200, 
 0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 
 0x1000000a, 0x121140, 0x3c02bfff, 0x3442ffff, 
 0x8f830200, 0x2028024, 0x2402fffd, 0x621824, 
-0xc003be0, 0xaf830200, 0x121140, 0x3c010001, 
-0x220821, 0x1000004b, 0xac306034, 0x128940, 
-0x3c050001, 0xb12821, 0x8ca56038, 0x3c100001, 
-0x2118021, 0x8e106030, 0x3c024000, 0xa21024, 
-0x14400010, 0x0, 0x3c020001, 0x8c423f68, 
+0xc003b0b, 0xaf830200, 0x121140, 0x3c010001, 
+0x220821, 0x1000004b, 0xac305f94, 0x128940, 
+0x3c050001, 0xb12821, 0x8ca55f98, 0x3c100001, 
+0x2118021, 0x8e105f90, 0x3c024000, 0xa21024, 
+0x14400010, 0x0, 0x3c020001, 0x8c423ec8, 
 0x14400005, 0x3c02bfff, 0x8f820200, 0x34420002, 
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003be0, 
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc003b0b, 
 0x2028024, 0x3c010001, 0x310821, 0x10000031, 
-0xac306030, 0x3c020001, 0x8c423f68, 0x10400005, 
-0x3c020020, 0x3c020001, 0x8c423eb4, 0x10400025, 
+0xac305f90, 0x3c020001, 0x8c423ec8, 0x10400005, 
+0x3c020020, 0x3c020001, 0x8c423e14, 0x10400025, 
 0x3c020020, 0xa21024, 0x10400007, 0x34840020, 
-0x24020100, 0x3c010001, 0x310821, 0xac226044, 
+0x24020100, 0x3c010001, 0x310821, 0xac225fa4, 
 0x10000006, 0x34840100, 0x3c010001, 0x310821, 
-0xac206044, 0x2402feff, 0x822024, 0x3c020080, 
+0xac205fa4, 0x2402feff, 0x822024, 0x3c020080, 
 0xa21024, 0x10400007, 0x121940, 0x3c020001, 
-0x3c010001, 0x230821, 0xac22604c, 0x10000008, 
+0x3c010001, 0x230821, 0xac225fac, 0x10000008, 
 0xc23025, 0x121140, 0x3c010001, 0x220821, 
-0xac20604c, 0x3c02fffe, 0x3442ffff, 0xc23024, 
+0xac205fac, 0x3c02fffe, 0x3442ffff, 0xc23024, 
 0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 
 0xaf820220, 0x121140, 0x3c010001, 0x220821, 
-0xac306030, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 
+0xac305f90, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0020, 0x1821, 
 0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, 
 0x30420001, 0x10400004, 0x0, 0x8f820044, 
@@ -8264,6 +8221,49 @@
 0xaf820044, 0x8f820044, 0x34420020, 0xaf820044, 
 0x8f820044, 0x451024, 0xaf820044, 0x24630001, 
 0x28620008, 0x5440ffee, 0x641007, 0x3e00008, 
+0x0, 0x0, 0x0, 0x8f8400c4, 
+0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824, 
+0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008, 
+0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004, 
+0x14400012, 0x805021, 0x8ce90000, 0x8f42013c, 
+0x1494823, 0x49182b, 0x94eb0006, 0x10600002, 
+0x25630050, 0x494821, 0x123182b, 0x50400003, 
+0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8, 
+0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008, 
+0x1021, 0x3e00008, 0x0, 0x8f8300e4, 
+0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e4, 
+0x3e00008, 0xaf8200e8, 0x27623000, 0xaf8200e4, 
+0x3e00008, 0xaf8200e8, 0x3e00008, 0x0, 
+0x27bdffd0, 0xafbf0028, 0x8f4c004c, 0x8f4d0048, 
+0xafb00024, 0x118d0026, 0x1ac4023, 0x8f490054, 
+0x5020001, 0x25080200, 0x189102b, 0x14400003, 
+0x24020200, 0x8004abe, 0x4c5023, 0x12c5023, 
+0x254affff, 0x10a102a, 0x54400001, 0x1005021, 
+0x14c8021, 0x321001ff, 0x8f45017c, 0x8f440178, 
+0xc1140, 0xa22821, 0x3406ecc0, 0xc23021, 
+0x2e63021, 0xa3940, 0x24031000, 0xafa30010, 
+0x8f430108, 0xafb00014, 0x8f420014, 0x60f809, 
+0xafa20018, 0x10400002, 0x8fbf0028, 0xaf50004c, 
+0x120d0003, 0x8fb00024, 0x3e00008, 0x27bd0030, 
+0xaf800048, 0x8f820048, 0x0, 0x1040fffc, 
+0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, 
+0xaf800048, 0x3e00008, 0x27bd0030, 0x3e00008, 
+0x0, 0x0, 0x0, 0x8f880120, 
+0x27624fe0, 0x8f830128, 0x15020002, 0x25090020, 
+0x27694800, 0x11230012, 0x8fa20010, 0xad040000, 
+0xad050004, 0xad060008, 0xa507000e, 0x8fa30014, 
+0xad020018, 0x8fa20018, 0xad03001c, 0x25030016, 
+0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc, 
+0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc, 
+0x8f430324, 0x1021, 0x24630001, 0x3e00008, 
+0xaf430324, 0x3e00008, 0x0, 0x8f880100, 
+0x276247e0, 0x8f830108, 0x15020002, 0x25090020, 
+0x27694000, 0x1123000f, 0x8fa20010, 0xad040000, 
+0xad050004, 0xad060008, 0xa507000e, 0x8fa30014, 
+0xad020018, 0x8fa20018, 0xad03001c, 0x25030016, 
+0xad020010, 0xad030014, 0xaf890100, 0x3e00008, 
+0x24020001, 0x8f430328, 0x1021, 0x24630001, 
+0x3e00008, 0xaf430328, 0x3e00008, 0x0, 
 0x0, 0x0, 0x0, 0x0 };
 u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
@@ -8368,12 +8368,12 @@
 0x0, 0x3f636d64, 0x48737453, 0x0, 
 0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64, 
 0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b, 
-0x0, 0x3f636d64, 0x45727200, 0x811c, 
-0x8898, 0x8898, 0x8820, 0x85c4, 
-0x886c, 0x8898, 0x81f4, 0x8258, 
-0x83dc, 0x84b4, 0x8480, 0x8898, 
-0x82bc, 0x8570, 0x8898, 0x8580, 
-0x8218, 0x827c, 0x0, 0x0, 
+0x0, 0x3f636d64, 0x45727200, 0x80fc, 
+0x8878, 0x8878, 0x8800, 0x85a4, 
+0x884c, 0x8878, 0x81d4, 0x8238, 
+0x83bc, 0x8494, 0x8460, 0x8878, 
+0x829c, 0x8550, 0x8878, 0x8560, 
+0x81f8, 0x825c, 0x0, 0x0, 
 0x0, 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
@@ -8424,10 +8424,10 @@
 0x2e313220, 0x31393939, 0x2f30312f, 0x32302031, 
 0x393a3439, 0x3a353120, 0x73687561, 0x6e672045, 
 0x78702024, 0x0, 0x46575f56, 0x45525349, 
-0x4f4e3a20, 0x23312054, 0x75652041, 0x70722032, 
-0x30203137, 0x3a32333a, 0x30322050, 0x44542031, 
+0x4f4e3a20, 0x23312054, 0x68752041, 0x75672031, 
+0x32203135, 0x3a35323a, 0x32392050, 0x44542031, 
 0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, 
-0x494d453a, 0x2031373a, 0x32333a30, 0x32000000, 
+0x494d453a, 0x2031353a, 0x35323a32, 0x39000000, 
 0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 
 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, 
 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, 
@@ -8503,22 +8503,22 @@
 0x6e495f46, 0x0, 0x5173436f, 0x6e734600, 
 0x51725072, 0x6f644600, 0x0, 0x0, 
 0x0, 0x50726f62, 0x65506879, 0x0, 
-0x6c6e6b41, 0x53535254, 0x0, 0xffc4, 
-0xfff4, 0x1000c, 0x10038, 0x10064, 
-0x10078, 0x100b4, 0x10454, 0x10234, 
-0x1026c, 0x10164, 0x102c0, 0x102e8, 
-0x1031c, 0x101a8, 0x10454, 0x10234, 
-0x1026c, 0x10290, 0x102c0, 0x102e8, 
-0x1031c, 0x10348, 0x0, 0x0, 
-0x0, 0x10a3c, 0x10b0c, 0x10be4, 
-0x10cb4, 0x10d10, 0x10dec, 0x10e14, 
-0x10ef0, 0x10f18, 0x110c0, 0x110e8, 
-0x11290, 0x11488, 0x1171c, 0x11630, 
-0x1171c, 0x11748, 0x112b8, 0x11460, 
-0x0, 0x11a4c, 0x11a8c, 0x11b1c, 
-0x11b60, 0x11bc4, 0x11c50, 0x11c84, 
-0x11d0c, 0x11da4, 0x11e74, 0x11eb4, 
-0x11f38, 0x11f5c, 0x1206c, 0x646f4261, 
+0x6c6e6b41, 0x53535254, 0x0, 0xfc78, 
+0xfca8, 0xfcc0, 0xfcec, 0xfd18, 
+0xfd2c, 0xfd68, 0x10108, 0xfee8, 
+0xff20, 0xfe18, 0xff74, 0xff9c, 
+0xffd0, 0xfe5c, 0x10108, 0xfee8, 
+0xff20, 0xff44, 0xff74, 0xff9c, 
+0xffd0, 0xfffc, 0x0, 0x0, 
+0x0, 0x106ec, 0x107bc, 0x10894, 
+0x10964, 0x109c0, 0x10a9c, 0x10ac4, 
+0x10ba0, 0x10bc8, 0x10d70, 0x10d98, 
+0x10f40, 0x11138, 0x113cc, 0x112e0, 
+0x113cc, 0x113f8, 0x10f68, 0x11110, 
+0x0, 0x116fc, 0x1173c, 0x117cc, 
+0x11810, 0x11874, 0x11900, 0x11934, 
+0x119bc, 0x11a54, 0x11b24, 0x11b64, 
+0x11be8, 0x11c0c, 0x11d1c, 0x646f4261, 
 0x73655067, 0x0, 0x0, 0x0, 
 0x0, 0x73746d61, 0x634c4e4b, 0x0, 
 0x0, 0x0 };
diff -u --recursive --new-file v2.3.16/linux/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- v2.3.16/linux/drivers/net/ariadne.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/ariadne.c	Sat Sep  4 13:08:32 1999
@@ -399,8 +399,8 @@
 
     board->Lance.RAP = CSR0;	/* PCnet-ISA Controller Status */
 
-    if (!(board->Lance.RDP & INTR))	/* Check if any interrupt has been
-	return;				   generated by the board. */
+    if (!(board->Lance.RDP & INTR))	/* Check if any interrupt has been */
+	return;				/* generated by the board. */
 
     if (dev->interrupt)
 	printk("%s: Re-entering the interrupt handler.\n", dev->name);
diff -u --recursive --new-file v2.3.16/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.3.16/linux/drivers/net/defxx.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/defxx.c	Thu Sep  2 10:02:32 1999
@@ -549,7 +549,7 @@
 
 				/* Get I/O base address from PCI Configuration Space */
 
-				port = pdev->resource[1].start
+				port = pdev->resource[1].start;
 
 				/* Verify port address range is not already being used */
 
diff -u --recursive --new-file v2.3.16/linux/drivers/net/eepro.c linux/drivers/net/eepro.c
--- v2.3.16/linux/drivers/net/eepro.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/eepro.c	Tue Sep  7 10:14:36 1999
@@ -23,6 +23,7 @@
 	This is a compatibility hardware problem.
 
 	Versions:
+	0.11e   some tweaks about multiple cards support (PdP, jul/aug 1999)
 	0.11d	added __initdata, __init stuff; call spin_lock_init
 	        in eepro_probe1. Replaced "eepro" by dev->name. Augmented 
 		the code protected by spin_lock in interrupt routine 
@@ -1661,17 +1662,10 @@
 #else
   0x200,  /* Why? */
 #endif
-  -1, -1, -1, -1, -1, -1, -1};
-static int irq[MAX_EEPRO] = {0, 0, 0, 0, 0, 0, 0, 0};
+  [1 ... MAX_EEPRO - 1] = -1 };
+static int irq[MAX_EEPRO] = { [0 ... MAX_EEPRO-1] = 0 };
 static int mem[MAX_EEPRO] = {	/* Size of the rx buffer in KB */
-  (RCV_RAM/1024),
-  (RCV_RAM/1024),
-  (RCV_RAM/1024),
-  (RCV_RAM/1024),
-  (RCV_RAM/1024),
-  (RCV_RAM/1024),
-  (RCV_RAM/1024),
-  (RCV_RAM/1024)
+  [0 ... MAX_EEPRO-1] = RCV_RAM/1024
 };
 
 static int n_eepro = 0;
@@ -1679,9 +1673,9 @@
 #if defined (LINUX_VERSION_CODE) && LINUX_VERSION_CODE > 0x20155
 MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)");
 MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver");
-MODULE_PARM(io, "i");
-MODULE_PARM(irq, "i");
-MODULE_PARM(mem, "i");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_EEPRO) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_EEPRO) "i");
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_EEPRO) "i");
 #endif 
 
 int 
diff -u --recursive --new-file v2.3.16/linux/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- v2.3.16/linux/drivers/net/hamradio/yam.c	Wed Aug 18 11:38:51 1999
+++ linux/drivers/net/hamradio/yam.c	Thu Sep  2 10:02:32 1999
@@ -131,7 +131,6 @@
 #else
 #define __init
 #define __initdata
-#define __initfunc(x) x
 #endif
 
 /* --------------------------------------------------------------------- */
@@ -1201,7 +1200,7 @@
 
 /* --------------------------------------------------------------------- */
 
-__initfunc(int yam_init(struct net_device *dev))
+int __init yam_init(struct net_device *dev)
 {
 	int i;
 
@@ -1267,7 +1266,7 @@
 
 #endif
 
-__initfunc(int init_module(void))
+int init_module(void)
 {
 	int ret = yam_init(NULL);
 
diff -u --recursive --new-file v2.3.16/linux/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- v2.3.16/linux/drivers/net/irda/toshoboe.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/net/irda/toshoboe.c	Tue Sep  7 10:14:36 1999
@@ -28,10 +28,22 @@
 /* an olivetti notebook which doesn't have FIR, a toshiba libretto, and */
 /* an hp printer, this works fine at 4MBPS with my HP printer */
 
-static char *rcsid = "$Id: toshoboe.c,v 1.5 1999/05/12 12:24:39 root Exp root $";
+static char *rcsid = "$Id: toshoboe.c,v 1.9 1999/06/29 14:21:06 root Exp $";
 
 /* 
  * $Log: toshoboe.c,v $
+ * Revision 1.9  1999/06/29 14:21:06  root
+ * *** empty log message ***
+ *
+ * Revision 1.8  1999/06/29 14:15:08  root
+ * *** empty log message ***
+ *
+ * Revision 1.7  1999/06/29 13:46:42  root
+ * *** empty log message ***
+ *
+ * Revision 1.6  1999/06/29 12:31:03  root
+ * *** empty log message ***
+ *
  * Revision 1.5  1999/05/12 12:24:39  root
  * *** empty log message ***
  *
@@ -93,6 +105,10 @@
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
 
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
 #include <net/irda/toshoboe.h>
 
 static char *driver_name = "toshoboe";
@@ -100,8 +116,10 @@
 static struct toshoboe_cb *dev_self[NSELFS + 1] =
 {NULL, NULL, NULL, NULL, NULL};
 
+static int max_baud = 4000000;
+
 /* Shutdown the chip and point the taskfile reg somewhere else */
-static void 
+static void
 toshoboe_stopchip (struct toshoboe_cb *self)
 {
   DEBUG (4, __FUNCTION__ "()\n");
@@ -117,16 +135,19 @@
   outb_p (0x00, OBOE_ISR);      /*FIXME: should i do this to disbale ints */
   outb_p (0x80, OBOE_RST);
   outb_p (0xe, OBOE_LOCK);
+
 }
 
 /*Set the baud rate */
-static void 
+static void
 toshoboe_setbaud (struct toshoboe_cb *self, int baud)
 {
+  unsigned long flags;
   DEBUG (4, __FUNCTION__ "()\n");
 
   printk (KERN_WARNING "ToshOboe: seting baud to %d\n", baud);
 
+  save_flags (flags);
   cli ();
   switch (baud)
     {
@@ -177,7 +198,7 @@
       break;
     }
 
-  sti ();
+  restore_flags (flags);
 
   outb_p (0x00, OBOE_RST);
   outb_p (0x80, OBOE_RST);
@@ -186,7 +207,7 @@
 }
 
 /* Wake the chip up and get it looking at the taskfile */
-static void 
+static void
 toshoboe_startchip (struct toshoboe_cb *self)
 {
   __u32 physaddr;
@@ -217,7 +238,7 @@
 }
 
 /*Let the chip look at memory */
-static void 
+static void
 toshoboe_enablebm (struct toshoboe_cb *self)
 {
   DEBUG (4, __FUNCTION__ "()\n");
@@ -225,7 +246,7 @@
 }
 
 /*Don't let the chip look at memory */
-static void 
+static void
 toshoboe_disablebm (struct toshoboe_cb *self)
 {
   __u8 command;
@@ -238,13 +259,15 @@
 }
 
 /*setup the taskfile */
-static void 
+static void
 toshoboe_initbuffs (struct toshoboe_cb *self)
 {
   int i;
+  unsigned long flags;
 
   DEBUG (4, __FUNCTION__ "()\n");
 
+  save_flags (flags);
   cli ();
 
   for (i = 0; i < TX_SLOTS; ++i)
@@ -261,12 +284,14 @@
       self->taskfile->recv[i].buffer = virt_to_bus (self->recv_bufs[i]);
     }
 
-  sti ();
+  restore_flags (flags);
 }
 
 
+
+
 /*Transmit something */
-static int 
+static int
 toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev)
 {
   struct irda_device *idev;
@@ -274,12 +299,17 @@
   int mtt, len;
 
   idev = (struct irda_device *) dev->priv;
-  ASSERT (idev != NULL, return 0;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+  ASSERT (idev != NULL, return 0;
+    );
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;
+    );
 
   self = idev->priv;
-  ASSERT (self != NULL, return 0;);
+  ASSERT (self != NULL, return 0;
+    );
 
+  if (self->stopped)
+    return 0;
 
 #ifdef ONETASK
   if (self->txpending)
@@ -343,7 +373,7 @@
 }
 
 /*interrupt handler */
-static void 
+static void
 toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
   struct irda_device *idev = (struct irda_device *) dev_id;
@@ -399,8 +429,9 @@
 #endif
         {
           int len = self->taskfile->recv[self->rxs].len;
-	
-	  if (len>2) len-=2;
+
+          if (len > 2)
+            len -= 2;
 
           skb = dev_alloc_skb (len + 1);
           if (skb)
@@ -459,27 +490,34 @@
 
 
 /* Change the baud rate */
-static void 
+static void
 toshoboe_change_speed (struct irda_device *idev, __u32 speed)
 {
   struct toshoboe_cb *self;
   DEBUG (4, __FUNCTION__ "()\n");
 
-  ASSERT (idev != NULL, return;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;);
+  ASSERT (idev != NULL, return;
+    );
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;
+    );
 
   self = idev->priv;
-  ASSERT (self != NULL, return;);
+  ASSERT (self != NULL, return;
+    );
+
 
   idev->io.baudrate = speed;
 
+  if (self->stopped)
+    return;
+
   toshoboe_setbaud (self, speed);
 
 }
 
 
 /* Check all xmit_tasks finished */
-static void 
+static void
 toshoboe_wait_until_sent (struct irda_device *idev)
 {
   struct toshoboe_cb *self;
@@ -487,11 +525,17 @@
 
   DEBUG (4, __FUNCTION__ "()\n");
 
-  ASSERT (idev != NULL, return;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;);
+  ASSERT (idev != NULL, return;
+    );
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return;
+    );
 
   self = idev->priv;
-  ASSERT (self != NULL, return;);
+  ASSERT (self != NULL, return;
+    );
+
+  if (self->stopped)
+    return;
 
   for (i = 0; i < TX_SLOTS; ++i)
     {
@@ -504,7 +548,7 @@
 
 }
 
-static int 
+static int
 toshoboe_is_receiving (struct irda_device *idev)
 {
   DEBUG (4, __FUNCTION__ "()\n");
@@ -514,7 +558,7 @@
 }
 
 
-static int 
+static int
 toshoboe_net_init (struct net_device *dev)
 {
   DEBUG (4, __FUNCTION__ "()\n");
@@ -527,37 +571,12 @@
 }
 
 
-
-
-static int 
-toshoboe_net_open (struct net_device *dev)
+static void 
+toshoboe_initptrs (struct toshoboe_cb *self)
 {
-  struct irda_device *idev;
-  struct toshoboe_cb *self;
-
-  DEBUG (4, __FUNCTION__ "()\n");
-
-  ASSERT (dev != NULL, return -1;);
-  idev = (struct irda_device *) dev->priv;
-
-  ASSERT (idev != NULL, return 0;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
-
-  self = idev->priv;
-  ASSERT (self != NULL, return 0;);
-
-  if (request_irq (idev->io.irq, toshoboe_interrupt,
-                   SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev))
-    {
-
-      return -EAGAIN;
-    }
-
-  toshoboe_initbuffs (self);
-  toshoboe_enablebm (self);
-  toshoboe_startchip (self);
-
 
+  unsigned long flags;
+  save_flags (flags);
   cli ();
 
   /*FIXME: need to test this carefully to check which one */
@@ -580,17 +599,59 @@
 
   self->txpending = 0;
 
-  sti ();
+  restore_flags (flags);
 
-  irda_device_net_open(dev);
+}
+
+
+static int
+toshoboe_net_open (struct net_device *dev)
+{
+  struct irda_device *idev;
+  struct toshoboe_cb *self;
+
+  DEBUG (4, __FUNCTION__ "()\n");
+
+  ASSERT (dev != NULL, return -1;
+    );
+  idev = (struct irda_device *) dev->priv;
+
+  ASSERT (idev != NULL, return 0;
+    );
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;
+    );
+
+  self = idev->priv;
+  ASSERT (self != NULL, return 0;
+    );
 
+  if (self->stopped)
+    return 0;
+
+
+  if (request_irq (idev->io.irq, toshoboe_interrupt,
+                   SA_SHIRQ | SA_INTERRUPT, idev->name, (void *) idev))
+    {
+
+      return -EAGAIN;
+    }
+
+  toshoboe_initbuffs (self);
+  toshoboe_enablebm (self);
+  toshoboe_startchip (self);
+  toshoboe_initptrs (self);
+
+  irda_device_net_open(dev);
+	
+  self->open = 1;
+	
   MOD_INC_USE_COUNT;
 
   return 0;
 
 }
 
-static int 
+static int
 toshoboe_net_close (struct net_device *dev)
 {
   struct irda_device *idev;
@@ -598,22 +659,31 @@
 
   DEBUG (4, __FUNCTION__ "()\n");
 
-  ASSERT (dev != NULL, return -1;);
+  ASSERT (dev != NULL, return -1;
+    );
   idev = (struct irda_device *) dev->priv;
 
-  ASSERT (idev != NULL, return 0;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+  ASSERT (idev != NULL, return 0;
+    );
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return 0;
+    );
 
   irda_device_net_close(dev);
 
   self = idev->priv;
 
-  ASSERT (self != NULL, return 0;);
+  ASSERT (self != NULL, return 0;
+    );
+
+  self->open = 0;
 
   free_irq (idev->io.irq, (void *) idev);
 
-  toshoboe_stopchip (self);
-  toshoboe_disablebm (self);
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+      toshoboe_disablebm (self);
+    }
 
   MOD_DEC_USE_COUNT;
 
@@ -625,7 +695,9 @@
 
 #ifdef MODULE
 
-static int 
+MODULE_PARM (max_baud, "i");
+
+static int
 toshoboe_close (struct irda_device *idev)
 {
   struct toshoboe_cb *self;
@@ -633,14 +705,21 @@
 
   DEBUG (4, __FUNCTION__ "()\n");
 
-  ASSERT (idev != NULL, return -1;);
-  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+  ASSERT (idev != NULL, return -1;
+    );
+  ASSERT (idev->magic == IRDA_DEVICE_MAGIC, return -1;
+    );
 
   self = idev->priv;
 
-  ASSERT (self != NULL, return -1;);
+  ASSERT (self != NULL, return -1;
+    );
 
-  toshoboe_stopchip (self);
+  if (!self->stopped)
+    {
+      toshoboe_stopchip (self);
+      toshoboe_disablebm (self);
+    }
 
   release_region (idev->io.iobase, idev->io.io_ext);
 
@@ -673,13 +752,13 @@
 
 
 
-static int 
+static int
 toshoboe_open (struct pci_dev *pci_dev)
 {
   struct toshoboe_cb *self;
   struct irda_device *idev;
   int i = 0;
-  int ok=0;
+  int ok = 0;
 
 
   DEBUG (4, __FUNCTION__ "()\n");
@@ -704,9 +783,10 @@
 
   memset (self, 0, sizeof (struct toshoboe_cb));
 
+  dev_self[i] = self;           /*This needs moving if we ever get more than one chip */
 
-  dev_self[i] = self;
-
+  self->open = 0;
+  self->stopped = 0;
   self->pdev = pci_dev;
   self->base = pci_dev->resource[0].start;
 
@@ -717,6 +797,7 @@
   idev->io.iobase = self->base;
   idev->io.irq = pci_dev->irq;
   idev->io.io_ext = CHIP_IO_EXTENT;
+  idev->io.baudrate = 9600;
 
   /* Lock the port that we need */
   i = check_region (idev->io.iobase, idev->io.io_ext);
@@ -731,16 +812,29 @@
       return -ENODEV;
     }
 
-  request_region (idev->io.iobase, idev->io.io_ext, driver_name);
 
   irda_init_max_qos_capabilies (&idev->qos);
+  idev->qos.baud_rate.bits = 0;
 
-  idev->qos.baud_rate.bits = IR_2400 | /*IR_4800 | */ IR_9600 | IR_19200 |
-    IR_115200;
+  if (max_baud >= 2400)
+    idev->qos.baud_rate.bits |= IR_2400;
+  /*if (max_baud>=4800) idev->qos.baud_rate.bits|=IR_4800; */
+  if (max_baud >= 9600)
+    idev->qos.baud_rate.bits |= IR_9600;
+  if (max_baud >= 19200)
+    idev->qos.baud_rate.bits |= IR_19200;
+  if (max_baud >= 115200)
+    idev->qos.baud_rate.bits |= IR_115200;
 #ifdef ENABLE_FAST
- idev->qos.baud_rate.bits|= IR_576000 | IR_1152000 | (IR_4000000 << 8);
+  if (max_baud >= 576000)
+    idev->qos.baud_rate.bits |= IR_576000;
+  if (max_baud >= 1152000)
+    idev->qos.baud_rate.bits |= IR_1152000;
+  if (max_baud >= 4000000)
+    idev->qos.baud_rate.bits |= (IR_4000000 << 8);
 #endif
 
+
   idev->qos.min_turn_time.bits = 0xff;  /*FIXME: what does this do? */
 
   irda_qos_bits_to_value (&idev->qos);
@@ -748,7 +842,8 @@
   idev->flags = IFF_SIR | IFF_DMA | IFF_PIO;
 
 #ifdef ENABLE_FAST
-  idev->flags |= IFF_FIR;
+  if (max_baud >= 576000)
+    idev->flags |= IFF_FIR;
 #endif
 
   /* These aren't much use as we need to have a whole panoply of
@@ -774,12 +869,13 @@
   self->txs = 0;
   self->rxs = 0;
 
-  self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL | GFP_DMA);
-  if (!self->taskfilebuf) {
-	printk(KERN_ERR "toshoboe: kmalloc for DMA failed()\n");
-	kfree(self);
-	return -ENOMEM;
-  }
+  self->taskfilebuf = kmalloc (OBOE_TASK_BUF_LEN, GFP_KERNEL);
+  if (!self->taskfilebuf)
+    {
+      printk (KERN_ERR "toshoboe: kmalloc for DMA failed()\n");
+      kfree (self);
+      return -ENOMEM;
+    }
 
 
   memset (self->taskfilebuf, 0, OBOE_TASK_BUF_LEN);
@@ -798,27 +894,35 @@
   for (i = 0; i < TX_SLOTS; ++i)
     {
       self->xmit_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA);
-      if (self->xmit_bufs[i]) ok++;
+      if (self->xmit_bufs[i])
+        ok++;
     }
 
   for (i = 0; i < RX_SLOTS; ++i)
     {
       self->recv_bufs[i] = kmalloc (TX_BUF_SZ, GFP_KERNEL | GFP_DMA);
-      if (self->recv_bufs[i]) ok++;
+      if (self->recv_bufs[i])
+        ok++;
     }
 
-  if (ok!=RX_SLOTS+TX_SLOTS) {
-	printk(KERN_ERR  "toshoboe: kmalloc for buffers failed()\n");
+  if (ok != RX_SLOTS + TX_SLOTS)
+    {
+      printk (KERN_ERR "toshoboe: kmalloc for buffers failed()\n");
 
 
-  for (i = 0; i < TX_SLOTS; ++i) if (self->xmit_bufs[i]) kfree(self->xmit_bufs[i]);
-  for (i = 0; i < RX_SLOTS; ++i) if (self->recv_bufs[i]) kfree(self->recv_bufs[i]);
+      for (i = 0; i < TX_SLOTS; ++i)
+        if (self->xmit_bufs[i])
+          kfree (self->xmit_bufs[i]);
+      for (i = 0; i < RX_SLOTS; ++i)
+        if (self->recv_bufs[i])
+          kfree (self->recv_bufs[i]);
 
-	kfree(self);
-	return -ENOMEM;
+      kfree (self);
+      return -ENOMEM;
 
-  }
+    }
 
+  request_region (idev->io.iobase, idev->io.io_ext, driver_name);
 
   irda_device_open (idev, driver_name, self);
 
@@ -833,6 +937,121 @@
   return (0);
 }
 
+#ifdef CONFIG_APM
+static void 
+toshoboe_gotosleep (struct toshoboe_cb *self)
+{
+  int i = 10;
+
+  printk (KERN_WARNING "ToshOboe: suspending\n");
+
+  if (self->stopped)
+    return;
+
+  self->stopped = 1;
+
+  if (!self->open)
+    return;
+
+/*FIXME: can't sleep here wait one second */
+
+  while ((i--) && (self->txpending))
+    udelay (100000);
+
+  toshoboe_stopchip (self);
+  toshoboe_disablebm (self);
+
+  self->txpending = 0;
+
+}
+
+
+static void 
+toshoboe_wakeup (struct toshoboe_cb *self)
+{
+  struct irda_device *idev = &self->idev;
+  struct net_device *dev = &idev->netdev;
+  unsigned long flags;
+
+  if (!self->stopped)
+    return;
+
+  if (!self->open)
+    {
+      self->stopped = 0;
+      return;
+    }
+
+  save_flags (flags);
+  cli ();
+
+  toshoboe_initbuffs (self);
+  toshoboe_enablebm (self);
+  toshoboe_startchip (self);
+
+  toshoboe_setbaud (self, idev->io.baudrate);
+
+  toshoboe_initptrs (self);
+
+
+
+  dev->tbusy = 0;
+  dev->interrupt = 0;
+  dev->start = 1;
+  self->stopped = 0;
+
+  restore_flags (flags);
+  printk (KERN_WARNING "ToshOboe: waking up\n");
+
+}
+
+static int 
+toshoboe_apmproc (apm_event_t event)
+{
+  static int down = 0;          /*Filter out double events */
+  int i;
+
+  switch (event)
+    {
+    case APM_SYS_SUSPEND:
+    case APM_USER_SUSPEND:
+      if (!down)
+        {
+
+          for (i = 0; i < 4; i++)
+            {
+              if (dev_self[i])
+                toshoboe_gotosleep (dev_self[i]);
+            }
+
+        }
+      down = 1;
+      break;
+    case APM_NORMAL_RESUME:
+    case APM_CRITICAL_RESUME:
+      if (down)
+        {
+
+
+
+          for (i = 0; i < 4; i++)
+            {
+              if (dev_self[i])
+                toshoboe_wakeup (dev_self[i]);
+            }
+
+
+
+        }
+      down = 0;
+      break;
+    }
+  return 0;
+}
+
+
+#endif
+
 int __init toshoboe_init (void)
 {
   struct pci_dev *pci_dev = NULL;
@@ -844,8 +1063,8 @@
                                  PCI_DEVICE_ID_FIR701, pci_dev);
       if (pci_dev)
         {
-          printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %ld\n",
-                  pci_dev->resource[0],
+          printk (KERN_WARNING "ToshOboe: Found 701 chip at 0x%0lx irq %d\n",
+                  pci_dev->resource[0].start,
                   pci_dev->irq);
 
           if (!toshoboe_open (pci_dev))
@@ -855,15 +1074,21 @@
     }
   while (pci_dev);
 
+
   if (found)
-    return 0;
+    {
+#ifdef CONFIG_APM
+      apm_register_callback (toshoboe_apmproc);
+#endif
+      return 0;
+    }
 
   return -ENODEV;
 }
 
 #ifdef MODULE
 
-static void 
+static void
 toshoboe_cleanup (void)
 {
   int i;
@@ -875,18 +1100,23 @@
       if (dev_self[i])
         toshoboe_close (&(dev_self[i]->idev));
     }
+
+#ifdef CONFIG_APM
+  apm_unregister_callback (toshoboe_apmproc);
+#endif
+
 }
 
 
 
-int 
+int
 init_module (void)
 {
   return toshoboe_init ();
 }
 
 
-void 
+void
 cleanup_module (void)
 {
   toshoboe_cleanup ();
diff -u --recursive --new-file v2.3.16/linux/drivers/net/plip.c linux/drivers/net/plip.c
--- v2.3.16/linux/drivers/net/plip.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/plip.c	Tue Sep  7 10:14:37 1999
@@ -2,17 +2,22 @@
 /* PLIP: A parallel port "network" driver for Linux. */
 /* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
 /*
- * Authors:	Donald Becker,  <becker@super.org>
- *		Tommy Thorn, <thorn@daimi.aau.dk>
- *		Tanabe Hiroyasu, <hiro@sanpo.t.u-tokyo.ac.jp>
- *		Alan Cox, <gw4pts@gw4pts.ampr.org>
- *		Peter Bauer, <100136.3530@compuserve.com>
- *		Niibe Yutaka, <gniibe@mri.co.jp>
+ * Authors:	Donald Becker <becker@super.org>
+ *		Tommy Thorn <thorn@daimi.aau.dk>
+ *		Tanabe Hiroyasu <hiro@sanpo.t.u-tokyo.ac.jp>
+ *		Alan Cox <gw4pts@gw4pts.ampr.org>
+ *		Peter Bauer <100136.3530@compuserve.com>
+ *		Niibe Yutaka <gniibe@mri.co.jp>
+ *		Nimrod Zimerman <zimerman@mailandnews.com>
  *
+ * Enhancements:
  *		Modularization and ifreq/ifmap support by Alan Cox.
  *		Rewritten by Niibe Yutaka.
- *              parport-sharing awareness code by Philip Blundell.
+ *		parport-sharing awareness code by Philip Blundell.
  *		SMP locking by Niibe Yutaka.
+ *		Support for parallel ports with no IRQ (poll mode),
+ *		Modifications to use the parallel port API 
+ *		by Nimrod Zimerman.
  *
  * Fixes:
  *		Niibe Yutaka
@@ -49,7 +54,7 @@
  *     To use with DOS box, please do (Turn on ARP switch):
  *	# ifconfig plip[0-2] arp
  */
-static const char *version = "NET3 PLIP version 2.3-parport gniibe@mri.co.jp\n";
+static const char *version = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n";
 
 /*
   Sources:
@@ -57,7 +62,7 @@
 	"parallel.asm" parallel port packet driver.
 
   The "Crynwr" parallel port standard specifies the following protocol:
-    Trigger by sending '0x08' (this cause interrupt on other end)
+    Trigger by sending nibble '0x8' (this causes interrupt on other end)
     count-low octet
     count-high octet
     ... data octets
@@ -93,7 +98,6 @@
 #include <linux/ptrace.h>
 #include <linux/if_ether.h>
 #include <asm/system.h>
-#include <asm/io.h>
 #include <linux/in.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
@@ -105,6 +109,7 @@
 #include <linux/inetdevice.h>
 #include <linux/skbuff.h>
 #include <linux/if_plip.h>
+#include <net/neighbour.h>
 
 #include <linux/tqueue.h>
 #include <linux/ioport.h>
@@ -112,6 +117,7 @@
 #include <asm/irq.h>
 #include <asm/byteorder.h>
 #include <asm/spinlock.h>
+#include <asm/semaphore.h>
 
 #include <linux/parport.h>
 
@@ -124,8 +130,8 @@
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
-#define ENABLE(irq) enable_irq(irq)
-#define DISABLE(irq) disable_irq(irq)
+#define ENABLE(irq)  if (irq != -1) enable_irq(irq)
+#define DISABLE(irq) if (irq != -1) disable_irq(irq)
 
 /* In micro second */
 #define PLIP_DELAY_UNIT		   1
@@ -136,22 +142,21 @@
 /* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
 #define PLIP_NIBBLE_WAIT        3000
 
-#define PAR_INTR_ON		(LP_PINITP|LP_PSELECP|LP_PINTEN)
-#define PAR_INTR_OFF		(LP_PINITP|LP_PSELECP)
-#define PAR_DATA(dev)		((dev)->base_addr+0)
-#define PAR_STATUS(dev)		((dev)->base_addr+1)
-#define PAR_CONTROL(dev)	((dev)->base_addr+2)
-
-/* Bottom halfs */
+/* Bottom halves */
 static void plip_kick_bh(struct net_device *dev);
 static void plip_bh(struct net_device *dev);
+static void plip_timer_bh(struct net_device *dev);
 
 /* Interrupt handler */
 static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 /* Functions for DEV methods */
-static int plip_rebuild_header(struct sk_buff *skb);
 static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
+static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,
+                            unsigned short type, void *daddr,
+                            void *saddr, unsigned len);
+static int plip_hard_header_cache(struct neighbour *neigh,
+                                  struct hh_cache *hh);
 static int plip_open(struct net_device *dev);
 static int plip_close(struct net_device *dev);
 static struct net_device_stats *plip_get_stats(struct net_device *dev);
@@ -210,6 +215,7 @@
 	struct net_device_stats enet_stats;
 	struct tq_struct immediate;
 	struct tq_struct deferred;
+	struct tq_struct timer;
 	struct plip_local snd_data;
 	struct plip_local rcv_data;
 	struct pardevice *pardev;
@@ -220,10 +226,52 @@
 	int is_deferred;
 	int port_owner;
 	int should_relinquish;
-	int (*orig_rebuild_header)(struct sk_buff *skb);
+	int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,
+	                        unsigned short type, void *daddr,
+	                        void *saddr, unsigned len);
+	int (*orig_hard_header_cache)(struct neighbour *neigh,
+	                              struct hh_cache *hh);
 	spinlock_t lock;
+	atomic_t kill_timer;
+	struct semaphore killed_timer_sem;
 };
 
+inline static void enable_parport_interrupts (struct net_device *dev)
+{
+	if (dev->irq != -1)
+	{
+		struct parport *port =
+		   ((struct net_local *)dev->priv)->pardev->port;
+		port->ops->enable_irq (port);
+	}
+}
+
+inline static void disable_parport_interrupts (struct net_device *dev)
+{
+	if (dev->irq != -1)
+	{
+		struct parport *port =
+		   ((struct net_local *)dev->priv)->pardev->port;
+		port->ops->disable_irq (port);
+	}
+}
+
+inline static void write_data (struct net_device *dev, unsigned char data)
+{
+	struct parport *port =
+	   ((struct net_local *)dev->priv)->pardev->port;
+
+	port->ops->write_data (port, data);
+}
+
+inline static unsigned char read_status (struct net_device *dev)
+{
+	struct parport *port =
+	   ((struct net_local *)dev->priv)->pardev->port;
+
+	return port->ops->read_status (port);
+}
+
 /* Entry point of PLIP driver.
    Probe the hardware, and register/initialize the driver.
 
@@ -243,8 +291,8 @@
 	dev->base_addr = pb->base;
 
 	if (pb->irq == -1) {
-		printk(KERN_INFO "plip: %s has no IRQ.\n", pb->name);
-		return -ENODEV;
+		printk(KERN_INFO "plip: %s has no IRQ. Using IRQ-less mode,"
+		                 "which is fairly inefficient!\n", pb->name);
 	}
 
 	pardev = parport_register_device(pb, dev->name, plip_preempt,
@@ -255,21 +303,26 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "%s", version);
-	printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
-	       dev->base_addr, dev->irq);
+	if (dev->irq != -1)
+		printk(KERN_INFO "%s: Parallel port at %#3lx, using IRQ %d.\n",
+		       dev->name, dev->base_addr, dev->irq);
+	else
+		printk(KERN_INFO "%s: Parallel port at %#3lx, not using IRQ.\n",
+		       dev->name, dev->base_addr);
 
 	/* Fill in the generic fields of the device structure. */
 	ether_setup(dev);
 
 	/* Then, override parts of it */
-	dev->hard_start_xmit	= plip_tx_packet;
-	dev->open		= plip_open;
-	dev->stop		= plip_close;
-	dev->get_stats 		= plip_get_stats;
-	dev->set_config		= plip_config;
-	dev->do_ioctl		= plip_ioctl;
-	dev->tx_queue_len	= 10;
-	dev->flags	        = IFF_POINTOPOINT|IFF_NOARP;
+	dev->hard_start_xmit	 = plip_tx_packet;
+	dev->open		 = plip_open;
+	dev->stop		 = plip_close;
+	dev->get_stats 		 = plip_get_stats;
+	dev->set_config		 = plip_config;
+	dev->do_ioctl		 = plip_ioctl;
+	dev->header_cache_update = NULL;
+	dev->tx_queue_len 	 = 10;
+	dev->flags	         = IFF_POINTOPOINT|IFF_NOARP;
 	memset(dev->dev_addr, 0xfc, ETH_ALEN);
 
 	/* Set the private structure */
@@ -282,8 +335,12 @@
 	memset(dev->priv, 0, sizeof(struct net_local));
 	nl = (struct net_local *) dev->priv;
 
-	nl->orig_rebuild_header = dev->rebuild_header;
-	dev->rebuild_header 	= plip_rebuild_header;
+	nl->orig_hard_header    = dev->hard_header;
+	dev->hard_header        = plip_hard_header;
+
+	nl->orig_hard_header_cache = dev->hard_header_cache;
+	dev->hard_header_cache     = plip_hard_header_cache;
+
 	nl->pardev = pardev; 
 
 	nl->port_owner = 0;
@@ -295,13 +352,21 @@
 	/* Initialize task queue structures */
 	nl->immediate.next = NULL;
 	nl->immediate.sync = 0;
-	nl->immediate.routine = (void *)(void *)plip_bh;
+	nl->immediate.routine = (void (*)(void *))plip_bh;
 	nl->immediate.data = dev;
 
 	nl->deferred.next = NULL;
 	nl->deferred.sync = 0;
-	nl->deferred.routine = (void *)(void *)plip_kick_bh;
+	nl->deferred.routine = (void (*)(void *))plip_kick_bh;
 	nl->deferred.data = dev;
+
+	if (dev->irq == -1) {
+		nl->timer.next = NULL;
+		nl->timer.sync = 0;
+		nl->timer.routine = (void (*)(void *))plip_timer_bh;
+		nl->timer.data = dev;
+	}
+
 	spin_lock_init(&nl->lock);
 
 	return 0;
@@ -373,6 +438,22 @@
 	}
 }
 
+static void
+plip_timer_bh(struct net_device *dev)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	
+	if (!(atomic_read (&nl->kill_timer))) {
+		if (!dev->interrupt)
+			plip_interrupt (-1, dev, NULL);
+
+		queue_task (&nl->timer, &tq_timer);
+	}
+	else {
+		up (&nl->killed_timer_sem);
+	}
+}
+
 static int
 plip_bh_timeout_error(struct net_device *dev, struct net_local *nl,
 		      struct plip_local *snd, struct plip_local *rcv,
@@ -401,7 +482,7 @@
 				/* Try again later */
 				return TIMEOUT;
 			}
-			c0 = inb(PAR_STATUS(dev));
+			c0 = read_status(dev);
 			printk(KERN_WARNING "%s: transmit timeout(%d,%02x)\n",
 			       dev->name, snd->state, c0);
 		} else
@@ -420,7 +501,7 @@
 				/* Try again later */
 				return TIMEOUT;
 			}
-			c0 = inb(PAR_STATUS(dev));
+			c0 = read_status(dev);
 			printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",
 			       dev->name, rcv->state, c0);
 		}
@@ -441,10 +522,10 @@
 		DISABLE(dev->irq);
 		synchronize_irq();
 	}
-	outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+	disable_parport_interrupts (dev);
 	dev->tbusy = 1;
 	nl->connection = PLIP_CN_ERROR;
-	outb(0x00, PAR_DATA(dev));
+	write_data (dev, 0x00);
 
 	return TIMEOUT;
 }
@@ -459,7 +540,7 @@
 /* PLIP_RECEIVE --- receive a byte(two nibbles)
    Returns OK on success, TIMEOUT on timeout */
 inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short status_addr,
+plip_receive(unsigned short nibble_timeout, struct net_device *dev,
 	     enum plip_nibble_state *ns_p, unsigned char *data_p)
 {
 	unsigned char c0, c1;
@@ -469,10 +550,10 @@
 	case PLIP_NB_BEGIN:
 		cx = nibble_timeout;
 		while (1) {
-			c0 = inb(status_addr);
+			c0 = read_status(dev);
 			udelay(PLIP_DELAY_UNIT);
 			if ((c0 & 0x80) == 0) {
-				c1 = inb(status_addr);
+				c1 = read_status(dev);
 				if (c0 == c1)
 					break;
 			}
@@ -480,17 +561,16 @@
 				return TIMEOUT;
 		}
 		*data_p = (c0 >> 3) & 0x0f;
-		outb(0x10, --status_addr); /* send ACK */
-		status_addr++;
+		write_data (dev, 0x10); /* send ACK */
 		*ns_p = PLIP_NB_1;
 
 	case PLIP_NB_1:
 		cx = nibble_timeout;
 		while (1) {
-			c0 = inb(status_addr);
+			c0 = read_status(dev);
 			udelay(PLIP_DELAY_UNIT);
 			if (c0 & 0x80) {
-				c1 = inb(status_addr);
+				c1 = read_status(dev);
 				if (c0 == c1)
 					break;
 			}
@@ -498,8 +578,7 @@
 				return TIMEOUT;
 		}
 		*data_p |= (c0 << 1) & 0xf0;
-		outb(0x00, --status_addr); /* send ACK */
-		status_addr++;
+		write_data (dev, 0x00); /* send ACK */
 		*ns_p = PLIP_NB_BEGIN;
 	case PLIP_NB_2:
 		break;
@@ -512,7 +591,6 @@
 plip_receive_packet(struct net_device *dev, struct net_local *nl,
 		    struct plip_local *snd, struct plip_local *rcv)
 {
-	unsigned short status_addr = PAR_STATUS(dev);
 	unsigned short nibble_timeout = nl->nibble;
 	unsigned char *lbuf;
 
@@ -520,9 +598,9 @@
 	case PLIP_PK_TRIGGER:
 		DISABLE(dev->irq);
 		/* Don't need to synchronize irq, as we can safely ignore it */
-		outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+		disable_parport_interrupts (dev);
 		dev->interrupt = 0;
-		outb(0x01, PAR_DATA(dev)); /* send ACK */
+		write_data (dev, 0x01); /* send ACK */
 		if (net_debug > 2)
 			printk(KERN_DEBUG "%s: receive start\n", dev->name);
 		rcv->state = PLIP_PK_LENGTH_LSB;
@@ -530,26 +608,26 @@
 
 	case PLIP_PK_LENGTH_LSB:
 		if (snd->state != PLIP_PK_DONE) {
-			if (plip_receive(nl->trigger, status_addr,
+			if (plip_receive(nl->trigger, dev,
 					 &rcv->nibble, &rcv->length.b.lsb)) {
 				/* collision, here dev->tbusy == 1 */
 				rcv->state = PLIP_PK_DONE;
 				nl->is_deferred = 1;
 				nl->connection = PLIP_CN_SEND;
 				queue_task(&nl->deferred, &tq_timer);
-				outb(PAR_INTR_ON, PAR_CONTROL(dev));
+				enable_parport_interrupts (dev);
 				ENABLE(dev->irq);
 				return OK;
 			}
 		} else {
-			if (plip_receive(nibble_timeout, status_addr,
+			if (plip_receive(nibble_timeout, dev,
 					 &rcv->nibble, &rcv->length.b.lsb))
 				return TIMEOUT;
 		}
 		rcv->state = PLIP_PK_LENGTH_MSB;
 
 	case PLIP_PK_LENGTH_MSB:
-		if (plip_receive(nibble_timeout, status_addr,
+		if (plip_receive(nibble_timeout, dev,
 				 &rcv->nibble, &rcv->length.b.msb))
 			return TIMEOUT;
 		if (rcv->length.h > dev->mtu + dev->hard_header_len
@@ -572,7 +650,7 @@
 	case PLIP_PK_DATA:
 		lbuf = rcv->skb->data;
 		do
-			if (plip_receive(nibble_timeout, status_addr,
+			if (plip_receive(nibble_timeout, dev,
 					 &rcv->nibble, &lbuf[rcv->byte]))
 				return TIMEOUT;
 		while (++rcv->byte < rcv->length.h);
@@ -582,7 +660,7 @@
 		rcv->state = PLIP_PK_CHECKSUM;
 
 	case PLIP_PK_CHECKSUM:
-		if (plip_receive(nibble_timeout, status_addr,
+		if (plip_receive(nibble_timeout, dev,
 				 &rcv->nibble, &rcv->data))
 			return TIMEOUT;
 		if (rcv->data != rcv->checksum) {
@@ -604,20 +682,20 @@
 			printk(KERN_DEBUG "%s: receive end\n", dev->name);
 
 		/* Close the connection. */
-		outb (0x00, PAR_DATA(dev));
+		write_data (dev, 0x00);
 		spin_lock_irq(&nl->lock);
 		if (snd->state != PLIP_PK_DONE) {
 			nl->connection = PLIP_CN_SEND;
 			spin_unlock_irq(&nl->lock);
 			queue_task(&nl->immediate, &tq_immediate);
 			mark_bh(IMMEDIATE_BH);
-			outb(PAR_INTR_ON, PAR_CONTROL(dev));
+			enable_parport_interrupts (dev);
 			ENABLE(dev->irq);
 			return OK;
 		} else {
 			nl->connection = PLIP_CN_NONE;
 			spin_unlock_irq(&nl->lock);
-			outb(PAR_INTR_ON, PAR_CONTROL(dev));
+			enable_parport_interrupts (dev);
 			ENABLE(dev->irq);
 			return OK;
 		}
@@ -628,7 +706,7 @@
 /* PLIP_SEND --- send a byte (two nibbles)
    Returns OK on success, TIMEOUT when timeout    */
 inline static int
-plip_send(unsigned short nibble_timeout, unsigned short data_addr,
+plip_send(unsigned short nibble_timeout, struct net_device *dev,
 	  enum plip_nibble_state *ns_p, unsigned char data)
 {
 	unsigned char c0;
@@ -636,37 +714,34 @@
 
 	switch (*ns_p) {
 	case PLIP_NB_BEGIN:
-		outb((data & 0x0f), data_addr);
+		write_data (dev, data & 0x0f);
 		*ns_p = PLIP_NB_1;
 
 	case PLIP_NB_1:
-		outb(0x10 | (data & 0x0f), data_addr);
+		write_data (dev, 0x10 | (data & 0x0f));
 		cx = nibble_timeout;
-		data_addr++;
 		while (1) {
-			c0 = inb(data_addr);
+			c0 = read_status(dev);
 			if ((c0 & 0x80) == 0)
 				break;
 			if (--cx == 0)
 				return TIMEOUT;
 			udelay(PLIP_DELAY_UNIT);
 		}
-		outb(0x10 | (data >> 4), --data_addr);
+		write_data (dev, 0x10 | (data >> 4));
 		*ns_p = PLIP_NB_2;
 
 	case PLIP_NB_2:
-		outb((data >> 4), data_addr);
-		data_addr++;
+		write_data (dev, (data >> 4));
 		cx = nibble_timeout;
 		while (1) {
-			c0 = inb(data_addr);
+			c0 = read_status(dev);
 			if (c0 & 0x80)
 				break;
 			if (--cx == 0)
 				return TIMEOUT;
 			udelay(PLIP_DELAY_UNIT);
 		}
-		data_addr--;
 		*ns_p = PLIP_NB_BEGIN;
 		return OK;
 	}
@@ -678,7 +753,6 @@
 plip_send_packet(struct net_device *dev, struct net_local *nl,
 		 struct plip_local *snd, struct plip_local *rcv)
 {
-	unsigned short data_addr = PAR_DATA(dev);
 	unsigned short nibble_timeout = nl->nibble;
 	unsigned char *lbuf;
 	unsigned char c0;
@@ -693,11 +767,11 @@
 
 	switch (snd->state) {
 	case PLIP_PK_TRIGGER:
-		if ((inb(PAR_STATUS(dev)) & 0xf8) != 0x80)
+		if ((read_status(dev) & 0xf8) != 0x80)
 			return HS_TIMEOUT;
 
 		/* Trigger remote rx interrupt. */
-		outb(0x08, data_addr);
+		write_data (dev, 0x08);
 		cx = nl->trigger;
 		while (1) {
 			udelay(PLIP_DELAY_UNIT);
@@ -708,7 +782,7 @@
 				nl->enet_stats.collisions++;
 				return OK;
 			}
-			c0 = inb(PAR_STATUS(dev));
+			c0 = read_status(dev);
 			if (c0 & 0x08) {
 				spin_unlock_irq(&nl->lock);
 				DISABLE(dev->irq);
@@ -724,7 +798,7 @@
 					nl->enet_stats.collisions++;
 					return OK;
 				}
-				outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+				disable_parport_interrupts (dev);
 				if (net_debug > 2)
 					printk(KERN_DEBUG "%s: send start\n", dev->name);
 				snd->state = PLIP_PK_LENGTH_LSB;
@@ -734,19 +808,19 @@
 			}
 			spin_unlock_irq(&nl->lock);
 			if (--cx == 0) {
-				outb(0x00, data_addr);
+				write_data (dev, 0x00);
 				return HS_TIMEOUT;
 			}
 		}
 
 	case PLIP_PK_LENGTH_LSB:
-		if (plip_send(nibble_timeout, data_addr,
+		if (plip_send(nibble_timeout, dev,
 			      &snd->nibble, snd->length.b.lsb))
 			return TIMEOUT;
 		snd->state = PLIP_PK_LENGTH_MSB;
 
 	case PLIP_PK_LENGTH_MSB:
-		if (plip_send(nibble_timeout, data_addr,
+		if (plip_send(nibble_timeout, dev,
 			      &snd->nibble, snd->length.b.msb))
 			return TIMEOUT;
 		snd->state = PLIP_PK_DATA;
@@ -755,7 +829,7 @@
 
 	case PLIP_PK_DATA:
 		do
-			if (plip_send(nibble_timeout, data_addr,
+			if (plip_send(nibble_timeout, dev,
 				      &snd->nibble, lbuf[snd->byte]))
 				return TIMEOUT;
 		while (++snd->byte < snd->length.h);
@@ -765,7 +839,7 @@
 		snd->state = PLIP_PK_CHECKSUM;
 
 	case PLIP_PK_CHECKSUM:
-		if (plip_send(nibble_timeout, data_addr,
+		if (plip_send(nibble_timeout, dev,
 			      &snd->nibble, snd->checksum))
 			return TIMEOUT;
 
@@ -776,14 +850,14 @@
 
 	case PLIP_PK_DONE:
 		/* Close the connection */
-		outb (0x00, data_addr);
+		write_data (dev, 0x00);
 		snd->skb = NULL;
 		if (net_debug > 2)
 			printk(KERN_DEBUG "%s: send end\n", dev->name);
 		nl->connection = PLIP_CN_CLOSING;
 		nl->is_deferred = 1;
 		queue_task(&nl->deferred, &tq_timer);
-		outb(PAR_INTR_ON, PAR_CONTROL(dev));
+		enable_parport_interrupts (dev);
 		ENABLE(dev->irq);
 		return OK;
 	}
@@ -815,7 +889,7 @@
 {
 	unsigned char status;
 
-	status = inb(PAR_STATUS(dev));
+	status = read_status(dev);
 	if ((status & 0xf8) == 0x80) {
 		if (net_debug > 2)
 			printk(KERN_DEBUG "%s: reset interface.\n", dev->name);
@@ -823,7 +897,7 @@
 		nl->should_relinquish = 0;
 		dev->tbusy = 0;
 		dev->interrupt = 0;
-		outb(PAR_INTR_ON, PAR_CONTROL(dev));
+		enable_parport_interrupts (dev);
 		ENABLE(dev->irq);
 		mark_bh(NET_BH);
 	} else {
@@ -854,9 +928,9 @@
 	if (dev->interrupt)
 		return;
 
-	c0 = inb(PAR_STATUS(dev));
+	c0 = read_status(dev);
 	if ((c0 & 0xf8) != 0xc0) {
-		if (net_debug > 1)
+		if ((dev->irq != -1) && (net_debug > 1))
 			printk(KERN_DEBUG "%s: spurious interrupt\n", dev->name);
 		return;
 	}
@@ -893,22 +967,6 @@
 	}
 }
 
-/* We don't need to send arp, for plip is point-to-point. */
-static int
-plip_rebuild_header(struct sk_buff *skb)
-{
-	struct net_device *dev = skb->dev;
-	struct net_local *nl = (struct net_local *)dev->priv;
-	struct ethhdr *eth = (struct ethhdr *)skb->data;
-
-	if ((dev->flags & IFF_NOARP)==0)
-		return nl->orig_rebuild_header(skb);
-
-	memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-	memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
-	return 0;
-}
-
 static int
 plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
 {
@@ -955,6 +1013,51 @@
 	return 0;
 }
 
+static void
+plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
+{
+	struct in_device *in_dev;
+
+	if ((in_dev=dev->ip_ptr) != NULL) {
+		/* Any address will do - we take the first */
+		struct in_ifaddr *ifa=in_dev->ifa_list;
+		if (ifa != NULL) {
+			memcpy(eth->h_source, dev->dev_addr, 6);
+			memset(eth->h_dest, 0xfc, 2);
+			memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
+		}
+	}
+}
+
+static int
+plip_hard_header(struct sk_buff *skb, struct net_device *dev,
+                 unsigned short type, void *daddr,
+	         void *saddr, unsigned len)
+{
+	struct net_local *nl = (struct net_local *)dev->priv;
+	int ret;
+
+	if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
+		plip_rewrite_address (dev, (struct ethhdr *)skb->data);
+
+	return ret;
+}
+
+int plip_hard_header_cache(struct neighbour *neigh,
+                           struct hh_cache *hh)
+{
+	struct net_local *nl = (struct net_local *)neigh->dev->priv;
+	int ret;
+	
+	if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
+	{
+		struct ethhdr *eth = (struct ethhdr*)(((u8*)hh->hh_data) + 2);
+		plip_rewrite_address (neigh->dev, eth);
+	}
+	
+	return ret;
+}                          
+
 /* Open/initialize the board.  This is called (in the current kernel)
    sometime after booting when the 'ifconfig' program is run.
 
@@ -976,10 +1079,15 @@
 	nl->should_relinquish = 0;
 
 	/* Clear the data port. */
-	outb (0x00, PAR_DATA(dev));
+	write_data (dev, 0x00);
 
 	/* Enable rx interrupt. */
-	outb(PAR_INTR_ON, PAR_CONTROL(dev));
+	enable_parport_interrupts (dev);
+	if (dev->irq == -1)
+	{
+		atomic_set (&nl->kill_timer, 0);
+		queue_task (&nl->timer, &tq_timer);
+	}
 
 	/* Initialize the state machine. */
 	nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
@@ -988,21 +1096,24 @@
 	nl->is_deferred = 0;
 
 	/* Fill in the MAC-level header.
-	   (ab)Use "dev->broadcast" to store point-to-point MAC address.
-
-	   PLIP doesn't have a real mac address, but we need to create one
-	   to be DOS compatible.  */
-	memset(dev->dev_addr,  0xfc, ETH_ALEN);
-	memset(dev->broadcast, 0xfc, ETH_ALEN);
+	   We used to abuse dev->broadcast to store the point-to-point
+	   MAC address, but we no longer do it. Instead, we fetch the
+	   interface address whenever it is needed, which is cheap enough
+	   because we use the hh_cache. Actually, abusing dev->broadcast
+	   didn't work, because when using plip_open the point-to-point
+	   address isn't yet known.
+	   PLIP doesn't have a real MAC address, but we need it to be
+	   DOS compatible, and to properly support taps (otherwise,
+	   when the device address isn't identical to the address of a
+	   received frame, the kernel incorrectly drops it).             */
 
 	if ((in_dev=dev->ip_ptr) != NULL) {
-		/*
-		 *	Any address will do - we take the first
-		 */
+		/* Any address will do - we take the first. We already
+		   have the first two bytes filled with 0xfc, from
+		   plip_init_dev(). */
 		struct in_ifaddr *ifa=in_dev->ifa_list;
 		if (ifa != NULL) {
 			memcpy(dev->dev_addr+2, &ifa->ifa_local, 4);
-			memcpy(dev->broadcast+2, &ifa->ifa_address, 4);
 		}
 	}
 
@@ -1027,6 +1138,13 @@
 	DISABLE(dev->irq);
 	synchronize_irq();
 
+	if (dev->irq == -1)
+	{
+		init_MUTEX_LOCKED (&nl->killed_timer_sem);
+		atomic_set (&nl->kill_timer, 1);
+		down (&nl->killed_timer_sem);
+	}
+
 #ifdef NOTDEF
 	outb(0x00, PAR_DATA(dev));
 #endif
@@ -1095,7 +1213,7 @@
 	if (!parport_claim(nl->pardev)) {
 		nl->port_owner = 1;
 		/* Clear the data port. */
-		outb (0x00, PAR_DATA(dev));
+		write_data (dev, 0x00);
 	}
 
 	return;
diff -u --recursive --new-file v2.3.16/linux/drivers/net/ppp_async.c linux/drivers/net/ppp_async.c
--- v2.3.16/linux/drivers/net/ppp_async.c	Thu Aug 26 13:05:38 1999
+++ linux/drivers/net/ppp_async.c	Thu Sep  2 09:25:13 1999
@@ -20,7 +20,7 @@
  * ==FILEVERSION 990806==
  */
 
-/* $Id$ */
+/* $Id: ppp_async.c,v 1.3 1999/09/02 05:30:10 paulus Exp $ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -895,8 +895,7 @@
 			/* stuff the chars in the skb */
 			skb = ap->rpkt;
 			if (skb == 0) {
-				skb = alloc_skb(ap->mru + PPP_HDRLEN + 2,
-						GFP_ATOMIC);
+				skb = dev_alloc_skb(ap->mru + PPP_HDRLEN + 2);
 				if (skb == 0)
 					goto nomem;
 				/* Try to get the payload 4-byte aligned */
diff -u --recursive --new-file v2.3.16/linux/drivers/net/ppp_generic.c linux/drivers/net/ppp_generic.c
--- v2.3.16/linux/drivers/net/ppp_generic.c	Wed Aug 18 11:36:42 1999
+++ linux/drivers/net/ppp_generic.c	Thu Sep  2 09:25:17 1999
@@ -22,7 +22,7 @@
  * ==FILEVERSION 990806==
  */
 
-/* $Id$ */
+/* $Id: ppp_generic.c,v 1.3 1999/09/02 05:30:12 paulus Exp $ */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -94,7 +94,7 @@
 	void		*rc_state;	/* its internal state */
 	unsigned long	last_xmit;	/* jiffies when last pkt sent */
 	unsigned long	last_recv;	/* jiffies when last pkt rcvd */
-	struct net_device	dev;		/* network interface device */
+	struct net_device *dev;		/* network interface device */
 	struct net_device_stats stats;	/* statistics */
 };
 
@@ -144,6 +144,7 @@
 static struct compressor *find_compressor(int type);
 static void ppp_get_stats(struct ppp *ppp, struct ppp_stats *st);
 static struct ppp *ppp_create_unit(int unit, int *retp);
+static void ppp_release_unit(struct ppp *ppp);
 static struct ppp *ppp_find_unit(int unit);
 
 /* Translates a PPP protocol number to a NP index (NP == network protocol) */
@@ -267,49 +268,11 @@
 static int ppp_release(struct inode *inode, struct file *file)
 {
 	struct ppp *ppp = (struct ppp *) file->private_data;
-	struct list_head *list, *next;
-	int ref;
-
-	if (ppp == 0)
-		goto out;
-	file->private_data = 0;
-	spin_lock(&all_ppp_lock);
-	ref = --ppp->refcnt;
-	if (ref == 0)
-		list_del(&ppp->list);
-	spin_unlock(&all_ppp_lock);
-	if (ref != 0)
-		goto out;
 
-	/* Last fd open to this ppp unit is being closed -
-	   mark the interface down, free the ppp unit */
-	rtnl_lock();
-	dev_close(&ppp->dev);
-	rtnl_unlock();
-	for (list = ppp->channels.next; list != &ppp->channels; list = next) {
-		/* forcibly detach this channel */
-		struct channel *chan;
-		chan = list_entry(list, struct channel, list);
-		chan->chan->ppp = 0;
-		next = list->next;
-		kfree(chan);
+	if (ppp != 0) {
+		file->private_data = 0;
+		ppp_release_unit(ppp);
 	}
-
-	/* Free up resources. */
-	ppp_ccp_closed(ppp);
-	lock_xmit_path(ppp);
-	lock_recv_path(ppp);
-	if (ppp->vj) {
-		slhc_free(ppp->vj);
-		ppp->vj = 0;
-	}
-	free_skbs(&ppp->xq);
-	free_skbs(&ppp->rq);
-	free_skbs(&ppp->recv_pending);
-	unregister_netdev(&ppp->dev);
-	kfree(ppp);
-
- out:
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -453,6 +416,12 @@
 		return -ENXIO;
 	err = -EFAULT;
 	switch (cmd) {
+	case PPPIOCDETACH:
+		file->private_data = 0;
+		ppp_release_unit(ppp);
+		err = 0;
+		break;
+
 	case PPPIOCSMRU:
 		if (get_user(val, (int *) arg))
 			break;
@@ -832,7 +801,7 @@
 	/* try to do packet compression */
 	if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
 	    && proto != PPP_LCP && proto != PPP_CCP) {
-		new_skb = alloc_skb(ppp->dev.mtu + PPP_HDRLEN, GFP_ATOMIC);
+		new_skb = alloc_skb(ppp->dev->mtu + PPP_HDRLEN, GFP_ATOMIC);
 		if (new_skb == 0) {
 			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
 			goto drop;
@@ -841,7 +810,7 @@
 		/* compressor still expects A/C bytes in hdr */
 		len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
 					   new_skb->data, skb->len + 2,
-					   ppp->dev.mtu + PPP_HDRLEN);
+					   ppp->dev->mtu + PPP_HDRLEN);
 		if (len > 0 && (ppp->flags & SC_CCP_UP)) {
 			kfree_skb(skb);
 			skb = new_skb;
@@ -853,6 +822,10 @@
 		}
 	}
 
+	/* for data packets, record the time */
+	if (proto < 0x8000)
+		ppp->last_xmit = jiffies;
+
 	/*
 	 * If we are waiting for traffic (demand dialling),
 	 * queue it up for pppd to receive.
@@ -994,7 +967,7 @@
 			goto err;
 		if (skb_tailroom(skb) < 124) {
 			/* copy to a new sk_buff with more tailroom */
-			ns = alloc_skb(skb->len + 128, GFP_ATOMIC);
+			ns = dev_alloc_skb(skb->len + 128);
 			if (ns == 0) {
 				printk(KERN_ERR"PPP: no memory (VJ decomp)\n");
 				goto err;
@@ -1051,12 +1024,12 @@
 	} else {
 		/* network protocol frame - give it to the kernel */
 		ppp->last_recv = jiffies;
-		if ((ppp->dev.flags & IFF_UP) == 0
+		if ((ppp->dev->flags & IFF_UP) == 0
 		    || ppp->npmode[npi] != NPMODE_PASS) {
 			kfree_skb(skb);
 		} else {
 			skb_pull(skb, 2);	/* chop off protocol */
-			skb->dev = &ppp->dev;
+			skb->dev = ppp->dev;
 			skb->protocol = htons(npindex_to_ethertype[npi]);
 			skb->mac.raw = skb->data;
 			netif_rx(skb);
@@ -1079,7 +1052,7 @@
 	int len;
 
 	if (proto == PPP_COMP) {
-		ns = alloc_skb(ppp->mru + PPP_HDRLEN, GFP_ATOMIC);
+		ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
 		if (ns == 0) {
 			printk(KERN_ERR "ppp_receive: no memory\n");
 			goto err;
@@ -1189,7 +1162,7 @@
 	if (trylock_xmit_path(ppp))
 		ppp_xmit_unlock(ppp);
 	if (ppp->xmit_pending == 0) {
-		ppp->dev.tbusy = 0;
+		ppp->dev->tbusy = 0;
 		mark_bh(NET_BH);
 	}
 }
@@ -1476,6 +1449,7 @@
 ppp_create_unit(int unit, int *retp)
 {
 	struct ppp *ppp;
+	struct net_device *dev;
 	struct list_head *list;
 	int last_unit = -1;
 	int ret = -EEXIST;
@@ -1501,6 +1475,12 @@
 	if (ppp == 0)
 		goto out;
 	memset(ppp, 0, sizeof(struct ppp));
+	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	if (dev == 0) {
+		kfree(ppp);
+		goto out;
+	}
+	memset(dev, 0, sizeof(struct net_device));
 
 	ppp->index = unit;
 	sprintf(ppp->name, "ppp%d", unit);
@@ -1514,13 +1494,18 @@
 	INIT_LIST_HEAD(&ppp->channels);
 	skb_queue_head_init(&ppp->recv_pending);
 
-	ppp->dev.init = ppp_net_init;
-	ppp->dev.name = ppp->name;
-	ppp->dev.priv = ppp;
+	ppp->dev = dev;
+	dev->init = ppp_net_init;
+	dev->name = ppp->name;
+	dev->priv = ppp;
+	dev->new_style = 1;
 
-	ret = register_netdev(&ppp->dev);
+	rtnl_lock();
+	ret = register_netdevice(dev);
+	rtnl_unlock();
 	if (ret != 0) {
 		printk(KERN_ERR "PPP: couldn't register device (%d)\n", ret);
+		kfree(dev);
 		kfree(ppp);
 		goto out;
 	}
@@ -1535,6 +1520,59 @@
 }
 
 /*
+ * Remove a reference to a ppp unit, and destroy it if
+ * the reference count goes to 0.
+ */
+static void ppp_release_unit(struct ppp *ppp)
+{
+	struct list_head *list, *next;
+	int ref;
+
+	spin_lock(&all_ppp_lock);
+	ref = --ppp->refcnt;
+	if (ref == 0)
+		list_del(&ppp->list);
+	spin_unlock(&all_ppp_lock);
+	if (ref != 0)
+		return;
+
+	/* Last fd open to this ppp unit is being closed or detached:
+	   mark the interface down, free the ppp unit */
+	if (ppp->dev) {
+		rtnl_lock();
+		dev_close(ppp->dev);
+		rtnl_unlock();
+	}
+	for (list = ppp->channels.next; list != &ppp->channels; list = next) {
+		/* forcibly detach this channel */
+		struct channel *chan;
+		chan = list_entry(list, struct channel, list);
+		chan->chan->ppp = 0;
+		next = list->next;
+		kfree(chan);
+	}
+
+	/* Free up resources. */
+	ppp_ccp_closed(ppp);
+	lock_xmit_path(ppp);
+	lock_recv_path(ppp);
+	if (ppp->vj) {
+		slhc_free(ppp->vj);
+		ppp->vj = 0;
+	}
+	free_skbs(&ppp->xq);
+	free_skbs(&ppp->rq);
+	free_skbs(&ppp->recv_pending);
+	if (ppp->dev) {
+		rtnl_lock();
+		unregister_netdevice(ppp->dev);
+		ppp->dev = 0;
+		rtnl_unlock();
+	}
+	kfree(ppp);
+}
+
+/*
  * Locate an existing ppp unit.
  * The caller should have locked the all_ppp_lock.
  */
@@ -1568,7 +1606,7 @@
 cleanup_module(void)
 {
 	/* should never happen */
-	if (all_ppp_units.next != &all_ppp_units)
+	if (!list_empty(&all_ppp_units))
 		printk(KERN_ERR "PPP: removing module but units remain!\n");
 	if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
 		printk(KERN_ERR "PPP: failed to unregister PPP device\n");
diff -u --recursive --new-file v2.3.16/linux/drivers/net/sun3lance.c linux/drivers/net/sun3lance.c
--- v2.3.16/linux/drivers/net/sun3lance.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/sun3lance.c	Sat Sep  4 13:08:32 1999
@@ -0,0 +1,885 @@
+/* sun3lance.c: Ethernet driver for SUN3 Lance chip */
+/*
+
+  Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net).  
+  This driver is a part of the linux kernel, and is thus distributed
+  under the GNU Public License.
+  
+  The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically
+  true for the correct IRQ and address of the lance registers.  They
+  have not been widely tested, however.  What we probably need is a
+  "proper" way to search for a device in the sun3's prom, but, alas,
+  linux has no such thing.  
+
+  This driver is largely based on atarilance.c, by Roman Hodek.  Other
+  sources of inspiration were the NetBSD sun3 am7990 driver, and the
+  linux sparc lance driver (sunlance.c).  
+
+  There are more assumptions made throughout this driver, it almost
+  certainly still needs work, but it does work at least for RARP/BOOTP and
+  mounting the root NFS filesystem.
+  
+*/
+
+static char *version = "sun3lance.c: v1.0 12/12/96  Sam Creasey (sammy@users.qual.net)\n";
+
+#include <linux/module.h>
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/idprom.h>
+#include <asm/pgtable.h>
+#include <asm/sun3mmu.h>
+#include <asm/dvma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* sun3/60 addr/irq for the lance chip.  If your sun is different,
+   change this. */
+#define LANCE_OBIO 0x120000
+#define LANCE_IRQ IRQ3
+
+/* Debug level:
+ *  0 = silent, print only serious errors
+ *  1 = normal, print error messages
+ *  2 = debug, print debug infos
+ *  3 = debug, print even more debug infos (packet data)
+ */
+
+#define	LANCE_DEBUG	1
+
+#ifdef LANCE_DEBUG
+static int lance_debug = LANCE_DEBUG;
+#else
+static int lance_debug = 1;
+#endif
+MODULE_PARM(lance_debug, "i");
+
+#define	DPRINTK(n,a) \
+	do {  \
+		if (lance_debug >= n)  \
+			printk a; \
+	} while( 0 )
+
+
+/* we're only using 32k of memory, so we use 4 TX
+   buffers and 16 RX buffers.  These values are expressed as log2. */
+
+#define TX_LOG_RING_SIZE			3
+#define RX_LOG_RING_SIZE			5
+
+/* These are the derived values */
+
+#define TX_RING_SIZE			(1 << TX_LOG_RING_SIZE)
+#define TX_RING_LEN_BITS		(TX_LOG_RING_SIZE << 5)
+#define	TX_RING_MOD_MASK		(TX_RING_SIZE - 1)
+
+#define RX_RING_SIZE			(1 << RX_LOG_RING_SIZE)
+#define RX_RING_LEN_BITS		(RX_LOG_RING_SIZE << 5)
+#define	RX_RING_MOD_MASK		(RX_RING_SIZE - 1)
+
+/* Definitions for packet buffer access: */
+#define PKT_BUF_SZ		1544
+
+/* Get the address of a packet buffer corresponding to a given buffer head */
+#define	PKTBUF_ADDR(head)	(void *)((unsigned long)(MEM) | (head)->base)
+
+
+/* The LANCE Rx and Tx ring descriptors. */
+struct lance_rx_head {
+	unsigned short	base;		/* Low word of base addr */
+	volatile unsigned char	flag;
+	unsigned char  base_hi;	/* High word of base addr (unused) */
+	short buf_length;	/* This length is 2s complement! */
+	volatile short msg_length;	/* This length is "normal". */
+};
+
+struct lance_tx_head {
+	unsigned short base;		/* Low word of base addr */
+	volatile unsigned char	flag;
+	unsigned char base_hi;	/* High word of base addr (unused) */
+	short length;		/* Length is 2s complement! */
+	volatile short misc;
+};
+
+/* The LANCE initialization block, described in databook. */
+struct lance_init_block {
+	unsigned short	mode;		/* Pre-set mode */
+	unsigned char	hwaddr[6];	/* Physical ethernet address */
+	unsigned int    filter[2];	/* Multicast filter (unused). */
+	/* Receive and transmit ring base, along with length bits. */
+	unsigned short rdra;
+	unsigned short rlen;
+	unsigned short tdra;
+	unsigned short tlen;
+	unsigned short pad[4]; /* is thie needed? */
+};
+
+/* The whole layout of the Lance shared memory */
+struct lance_memory {
+	struct lance_init_block	init;
+	struct lance_tx_head	tx_head[TX_RING_SIZE];
+	struct lance_rx_head	rx_head[RX_RING_SIZE];
+	char   rx_data[RX_RING_SIZE][PKT_BUF_SZ];
+	char   tx_data[RX_RING_SIZE][PKT_BUF_SZ];
+};
+
+/* The driver's private device structure */
+
+struct lance_private {
+	volatile unsigned short	*iobase;
+	struct lance_memory	*mem;
+     	int new_rx, new_tx;	/* The next free ring entry */
+	int old_tx, old_rx;     /* ring entry to be processed */
+	struct net_device_stats stats;
+/* These two must be ints for set_bit() */
+	int					tx_full;
+	int					lock;
+};
+
+/* I/O register access macros */
+
+#define	MEM	lp->mem
+#define	DREG	lp->iobase[0]
+#define	AREG	lp->iobase[1]
+#define	REGA(a)	( AREG = (a), DREG )
+
+/* Definitions for the Lance */
+
+/* tx_head flags */
+#define TMD1_ENP		0x01	/* end of packet */
+#define TMD1_STP		0x02	/* start of packet */
+#define TMD1_DEF		0x04	/* deferred */
+#define TMD1_ONE		0x08	/* one retry needed */
+#define TMD1_MORE		0x10	/* more than one retry needed */
+#define TMD1_ERR		0x40	/* error summary */
+#define TMD1_OWN 		0x80	/* ownership (set: chip owns) */
+
+#define TMD1_OWN_CHIP	TMD1_OWN
+#define TMD1_OWN_HOST	0
+
+/* tx_head misc field */
+#define TMD3_TDR		0x03FF	/* Time Domain Reflectometry counter */
+#define TMD3_RTRY		0x0400	/* failed after 16 retries */
+#define TMD3_LCAR		0x0800	/* carrier lost */
+#define TMD3_LCOL		0x1000	/* late collision */
+#define TMD3_UFLO		0x4000	/* underflow (late memory) */
+#define TMD3_BUFF		0x8000	/* buffering error (no ENP) */
+
+/* rx_head flags */
+#define RMD1_ENP		0x01	/* end of packet */
+#define RMD1_STP		0x02	/* start of packet */
+#define RMD1_BUFF		0x04	/* buffer error */
+#define RMD1_CRC		0x08	/* CRC error */
+#define RMD1_OFLO		0x10	/* overflow */
+#define RMD1_FRAM		0x20	/* framing error */
+#define RMD1_ERR		0x40	/* error summary */
+#define RMD1_OWN 		0x80	/* ownership (set: ship owns) */
+
+#define RMD1_OWN_CHIP	RMD1_OWN
+#define RMD1_OWN_HOST	0
+
+/* register names */
+#define CSR0	0		/* mode/status */
+#define CSR1	1		/* init block addr (low) */
+#define CSR2	2		/* init block addr (high) */
+#define CSR3	3		/* misc */
+#define CSR8	8	  	/* address filter */
+#define CSR15	15		/* promiscuous mode */
+
+/* CSR0 */
+/* (R=readable, W=writeable, S=set on write, C=clear on write) */
+#define CSR0_INIT	0x0001		/* initialize (RS) */
+#define CSR0_STRT	0x0002		/* start (RS) */
+#define CSR0_STOP	0x0004		/* stop (RS) */
+#define CSR0_TDMD	0x0008		/* transmit demand (RS) */
+#define CSR0_TXON	0x0010		/* transmitter on (R) */
+#define CSR0_RXON	0x0020		/* receiver on (R) */
+#define CSR0_INEA	0x0040		/* interrupt enable (RW) */
+#define CSR0_INTR	0x0080		/* interrupt active (R) */
+#define CSR0_IDON	0x0100		/* initialization done (RC) */
+#define CSR0_TINT	0x0200		/* transmitter interrupt (RC) */
+#define CSR0_RINT	0x0400		/* receiver interrupt (RC) */
+#define CSR0_MERR	0x0800		/* memory error (RC) */
+#define CSR0_MISS	0x1000		/* missed frame (RC) */
+#define CSR0_CERR	0x2000		/* carrier error (no heartbeat :-) (RC) */
+#define CSR0_BABL	0x4000		/* babble: tx-ed too many bits (RC) */
+#define CSR0_ERR	0x8000		/* error (RC) */
+
+/* CSR3 */
+#define CSR3_BCON	0x0001		/* byte control */
+#define CSR3_ACON	0x0002		/* ALE control */
+#define CSR3_BSWP	0x0004		/* byte swap (1=big endian) */
+
+/***************************** Prototypes *****************************/
+
+static int lance_probe( struct net_device *dev);
+static int lance_open( struct net_device *dev );
+static void lance_init_ring( struct net_device *dev );
+static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
+static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
+static int lance_rx( struct net_device *dev );
+static int lance_close( struct net_device *dev );
+static struct net_device_stats *lance_get_stats( struct net_device *dev );
+static void set_multicast_list( struct net_device *dev );
+
+/************************* End of Prototypes **************************/
+
+__initfunc(int sun3lance_probe( struct net_device *dev ))
+{	
+	static int found = 0;
+
+	if(found)
+		return(ENODEV);
+
+	if (lance_probe(dev)) {
+			found = 1;
+			return( 0 );
+	}
+
+	return( ENODEV );
+}
+
+__initfunc(static int lance_probe( struct net_device *dev))
+{	
+	unsigned long ioaddr, iopte;
+	
+	struct lance_private	*lp;
+	int 			i;
+	static int 		did_version = 0;
+	int found = 0;
+
+	/* LANCE_OBIO can be found within the IO pmeg with some effort */
+	for(ioaddr = 0xfe00000; ioaddr < (0xfe00000 +
+	    SUN3_PMEG_SIZE); ioaddr += SUN3_PTE_SIZE) {
+
+		iopte = sun3_get_pte(ioaddr);
+		if(!(iopte & SUN3_PAGE_TYPE_IO)) /* this an io page? */
+			continue;
+
+		if(((iopte & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT) ==
+		   LANCE_OBIO) {
+			found = 1;
+			break;
+		}
+	}
+	
+	if(!found)
+		return 0;
+
+	init_etherdev( dev, sizeof(struct lance_private) );
+	if (!dev->priv)
+		dev->priv = kmalloc( sizeof(struct lance_private), GFP_KERNEL );
+	lp = (struct lance_private *)dev->priv;
+	MEM = (struct lance_memory *)sun3_dvma_malloc(sizeof(struct
+							     lance_memory)); 
+	lp->iobase = (volatile unsigned short *)ioaddr;
+	dev->base_addr = (unsigned long)ioaddr; /* informational only */
+
+	REGA(CSR0) = CSR0_STOP; 
+
+	request_irq(LANCE_IRQ, lance_interrupt, 0, "SUN3 Lance", dev);
+	dev->irq = (unsigned short)LANCE_IRQ;
+
+
+	printk("%s: SUN3 Lance at io %#lx, mem %#lx, irq %d, hwaddr ",
+		   dev->name,
+		   (unsigned long)ioaddr,
+		   (unsigned long)MEM,
+		   dev->irq);
+
+	/* copy in the ethernet address from the prom */
+	for(i = 0; i < 6 ; i++)
+	     dev->dev_addr[i] = idprom->id_ethaddr[i];
+	
+	/* tell the card it's ether address, bytes swapped */
+	MEM->init.hwaddr[0] = dev->dev_addr[1];
+	MEM->init.hwaddr[1] = dev->dev_addr[0];
+	MEM->init.hwaddr[2] = dev->dev_addr[3];
+	MEM->init.hwaddr[3] = dev->dev_addr[2];
+	MEM->init.hwaddr[4] = dev->dev_addr[5];
+	MEM->init.hwaddr[5] = dev->dev_addr[4];
+
+	for( i = 0; i < 6; ++i )
+		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+
+	MEM->init.mode = 0x0000;
+	MEM->init.filter[0] = 0x00000000;
+	MEM->init.filter[1] = 0x00000000;
+	MEM->init.rdra = sun3_dvma_vtop(MEM->rx_head);
+	MEM->init.rlen    = (RX_LOG_RING_SIZE << 13) |
+		(sun3_dvma_vtop(MEM->rx_head) >> 16);
+	MEM->init.tdra = sun3_dvma_vtop(MEM->tx_head);
+	MEM->init.tlen    = (TX_LOG_RING_SIZE << 13) |
+		(sun3_dvma_vtop(MEM->tx_head) >> 16);
+
+	DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
+	       sun3_dvma_vtop(&(MEM->init)), sun3_dvma_vtop(MEM->rx_head),
+	       (sun3_dvma_vtop(MEM->tx_head))));  
+
+
+	if (did_version++ == 0)
+		DPRINTK( 1, ( version ));
+
+	/* The LANCE-specific entries in the device structure. */
+	dev->open = &lance_open;
+	dev->hard_start_xmit = &lance_start_xmit;
+	dev->stop = &lance_close;
+	dev->get_stats = &lance_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+	dev->set_mac_address = 0;
+	dev->start = 0;
+
+	memset( &lp->stats, 0, sizeof(lp->stats) );
+
+	return 1;
+}
+
+static int lance_open( struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int i;
+
+	DPRINTK( 2, ( "%s: lance_open()\n", dev->name ));
+
+	REGA(CSR0) = CSR0_STOP;
+
+	/* tell the lance the address of its init block */
+	REGA(CSR1) = sun3_dvma_vtop(&(MEM->init));
+	REGA(CSR2) = sun3_dvma_vtop(&(MEM->init)) >> 16;
+
+	lance_init_ring(dev);
+
+	/* Re-initialize the LANCE, and start it when done. */
+
+	REGA(CSR3) = CSR3_BSWP;
+
+	/* From now on, AREG is kept to point to CSR0 */
+	REGA(CSR0) = CSR0_INIT;
+
+	i = 1000000;
+	while (--i > 0)
+		if (DREG & CSR0_IDON)
+			break;
+	if (i < 0 || (DREG & CSR0_ERR)) {
+		DPRINTK( 2, ( "lance_open(): opening %s failed, i=%d, csr0=%04x\n",
+					  dev->name, i, DREG ));
+		DREG = CSR0_STOP;
+		return( -EIO );
+	}
+
+	DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
+	MOD_INC_USE_COUNT;
+
+	return( 0 );
+}
+
+
+/* Initialize the LANCE Rx and Tx rings. */
+
+static void lance_init_ring( struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int i;
+
+	lp->lock = 0;
+	lp->tx_full = 0;
+	lp->new_rx = lp->new_tx = 0;
+	lp->old_rx = lp->old_tx = 0;
+
+	for( i = 0; i < TX_RING_SIZE; i++ ) {
+		MEM->tx_head[i].base = sun3_dvma_vtop(MEM->tx_data[i]);
+		MEM->tx_head[i].flag = 0;
+ 		MEM->tx_head[i].base_hi = 
+			(sun3_dvma_vtop(MEM->tx_data[i])) >>16;
+		MEM->tx_head[i].length = 0;
+		MEM->tx_head[i].misc = 0;
+	}
+
+	for( i = 0; i < RX_RING_SIZE; i++ ) {
+		MEM->rx_head[i].base = sun3_dvma_vtop(MEM->rx_data[i]);
+		MEM->rx_head[i].flag = TMD1_OWN_CHIP;
+		MEM->rx_head[i].base_hi = 
+			(sun3_dvma_vtop(MEM->rx_data[i])) >> 16;
+		MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
+		MEM->rx_head[i].msg_length = 0;
+	}
+
+}
+
+
+static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int entry, len;
+	struct lance_tx_head *head;
+	unsigned long flags;
+
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 20)
+			return( 1 );
+
+		DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
+					  dev->name, DREG ));
+		DREG = CSR0_STOP;
+		/*
+		 * Always set BSWP after a STOP as STOP puts it back into
+		 * little endian mode.
+		 */
+		REGA(CSR3) = CSR3_BSWP;
+		lp->stats.tx_errors++;
+
+		if(lance_debug >= 2) {
+			int i;
+			printk("Ring data: old_tx %d new_tx %d%s new_rx %d\n",
+			       lp->old_tx, lp->new_tx,
+			       lp->tx_full ? " (full)" : "",
+			       lp->new_rx );
+			for( i = 0 ; i < RX_RING_SIZE; i++ )
+				printk( "rx #%d: base=%04x blen=%04x mlen=%04x\n",
+					i, MEM->rx_head[i].base,
+					-MEM->rx_head[i].buf_length,
+					MEM->rx_head[i].msg_length);
+			for( i = 0 ; i < TX_RING_SIZE; i++ )
+				printk("tx #%d: base=%04x len=%04x misc=%04x\n",
+				       i, MEM->tx_head[i].base,
+				       -MEM->tx_head[i].length,
+				       MEM->tx_head[i].misc );
+		}
+
+		lance_init_ring(dev);
+		REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
+		
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+		
+		return 0;
+	}
+	
+	AREG = CSR0;
+//	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
+//				  dev->name, DREG ));
+	
+	/* Block a timer-based transmit from overlapping.  This could better be
+	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit( 0, (void*)&dev->tbusy ) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+
+	if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
+		printk( "%s: tx queue lock!.\n", dev->name);
+		/* don't clear dev->tbusy flag. */
+		return 1;
+	}
+
+	/* Fill in a Tx ring entry */
+#if 0
+	if (lance_debug >= 3) {
+		u_char *p;
+		int i;
+		printk( "%s: TX pkt %d type 0x%04x from ", dev->name,
+			lp->new_tx, ((u_short *)skb->data)[6]);
+		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
+			printk("%02x%s", *p++, i != 5 ? ":" : "" );
+		printk(" to ");
+		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
+			printk("%02x%s", *p++, i != 5 ? ":" : "" );
+		printk(" data at 0x%08x len %d\n", (int)skb->data,
+		       (int)skb->len );
+	}
+#endif	
+	/* We're not prepared for the int until the last flags are set/reset.
+	 * And the int may happen already after setting the OWN_CHIP... */
+	save_and_cli(flags);
+
+	/* Mask to ring buffer boundary. */
+	entry = lp->new_tx;
+	head  = &(MEM->tx_head[entry]);
+
+	/* Caution: the write order is important here, set the "ownership" bits
+	 * last.
+	 */
+
+	/* the sun3's lance needs it's buffer padded to the minimum
+	   size */
+	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+//	head->length = -len;
+	head->length = (-len) | 0xf000;
+	head->misc = 0;
+
+	memcpy( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
+	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
+	lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
+	lp->stats.tx_bytes += skb->len;
+
+	/* Trigger an immediate send poll. */
+	REGA(CSR0) = CSR0_INEA | CSR0_TDMD;
+	dev->trans_start = jiffies;
+	dev_kfree_skb( skb );
+
+	lp->lock = 0;
+	if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
+	    TMD1_OWN_HOST) 
+		dev->tbusy = 0;
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/* The LANCE interrupt handler. */
+
+static void lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
+{
+	struct net_device *dev = dev_id;
+	struct lance_private *lp = dev->priv;
+	int csr0;
+
+	if (dev == NULL) {
+		DPRINTK( 1, ( "lance_interrupt(): invalid dev_id\n" ));
+		return;
+	}
+
+	if (dev->interrupt)
+		DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
+	dev->interrupt = 1;
+
+ still_more:
+
+	AREG = CSR0;
+	csr0 = DREG;
+
+	/* ack interrupts */
+	DREG = csr0 & (CSR0_TINT | CSR0_RINT);
+
+	/* clear errors */
+	if(csr0 & CSR0_ERR)
+		DREG = CSR0_BABL | CSR0_MERR | CSR0_CERR | CSR0_MISS;
+
+
+	DPRINTK( 2, ( "%s: interrupt  csr0=%04x new csr=%04x.\n",
+		      dev->name, csr0, DREG ));
+
+	if (csr0 & CSR0_TINT) {			/* Tx-done interrupt */
+		int old_tx = lp->old_tx;
+
+//		if(lance_debug >= 3) {
+//			int i;
+//			
+//			printk("%s: tx int\n", dev->name);
+//			
+//			for(i = 0; i < TX_RING_SIZE; i++)
+//				printk("ring %d flag=%04x\n", i,
+//				       MEM->tx_head[i].flag);
+//		}
+		
+		while( old_tx != lp->new_tx) {
+			struct lance_tx_head *head = &(MEM->tx_head[old_tx]); 
+			
+			DPRINTK(3, ("on tx_ring %d\n", old_tx));
+
+			if (head->flag & TMD1_OWN_CHIP)
+				break; /* It still hasn't been Txed */
+				
+			if (head->flag & TMD1_ERR) {
+				int status = head->misc;
+				lp->stats.tx_errors++;
+				if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+				if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+				if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+				if (status & (TMD3_UFLO | TMD3_BUFF)) {
+					lp->stats.tx_fifo_errors++;
+					printk("%s: Tx FIFO error\n",
+					       dev->name); 
+					REGA(CSR0) = CSR0_STOP;
+					REGA(CSR3) = CSR3_BSWP;
+					lance_init_ring(dev);
+					REGA(CSR0) = CSR0_STRT | CSR0_INEA;
+					return;
+				}
+			} else if(head->flag & (TMD1_ENP | TMD1_STP)) {
+				
+				head->flag &= ~(TMD1_ENP | TMD1_STP);
+				if(head->flag & (TMD1_ONE | TMD1_MORE))
+					lp->stats.collisions++;
+				
+				lp->stats.tx_packets++;
+				DPRINTK(3, ("cleared tx ring %d\n", old_tx));
+			}
+			old_tx = (old_tx +1) & TX_RING_MOD_MASK;
+		}
+
+		lp->old_tx = old_tx;
+	}
+
+
+	if (dev->tbusy) {
+		/* The ring is no longer full, clear tbusy. */
+		dev->tbusy = 0;
+		mark_bh( NET_BH );
+	}
+
+	if (csr0 & CSR0_RINT)			/* Rx interrupt */
+		lance_rx( dev );
+	
+	/* Log misc errors. */
+	if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
+	if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+	if (csr0 & CSR0_MERR) {
+		DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
+			      "status %04x.\n", dev->name, csr0 ));
+		/* Restart the chip. */
+		REGA(CSR0) = CSR0_STOP;
+		REGA(CSR3) = CSR3_BSWP;
+		lance_init_ring(dev);
+		REGA(CSR0) = CSR0_STRT | CSR0_INEA;
+	}
+
+
+    /* Clear any other interrupt, and set interrupt enable. */
+//	DREG = CSR0_BABL | CSR0_CERR | CSR0_MISS | CSR0_MERR |
+//		   CSR0_IDON | CSR0_INEA;
+
+	REGA(CSR0) = CSR0_INEA;
+
+	if(DREG & (CSR0_RINT | CSR0_TINT)) {
+	     DPRINTK(2, ("restarting interrupt, csr0=%#04x\n", DREG));
+	     goto still_more;
+	}
+
+	DPRINTK( 2, ( "%s: exiting interrupt, csr0=%#04x.\n",
+				  dev->name, DREG ));
+	dev->interrupt = 0;
+	return;
+}
+
+/* get packet, toss into skbuff */
+static int lance_rx( struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+	int entry = lp->new_rx;
+
+	/* If we own the next entry, it's a new packet. Send it up. */
+	while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
+		struct lance_rx_head *head = &(MEM->rx_head[entry]);
+		int status = head->flag;
+		
+		if (status != (RMD1_ENP|RMD1_STP)) {  /* There was an error. */
+			/* There is a tricky error noted by John Murphy,
+			   <murf@perftech.com> to Russ Nelson: Even with 
+			   full-sized buffers it's possible for a jabber packet to use two
+			   buffers, with only the last correctly noting the error. */
+			if (status & RMD1_ENP)	/* Only count a general error at the */
+				lp->stats.rx_errors++; /* end of a packet.*/
+			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
+			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
+			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
+			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+			head->flag &= (RMD1_ENP|RMD1_STP);
+		} else {
+			/* Malloc up new buffer, compatible with net-3. */
+//			short pkt_len = head->msg_length;// & 0xfff;
+			short pkt_len = (head->msg_length & 0xfff) - 4;
+			struct sk_buff *skb;
+
+			if (pkt_len < 60) {
+				printk( "%s: Runt packet!\n", dev->name );
+				lp->stats.rx_errors++;
+			}
+			else {
+				skb = dev_alloc_skb( pkt_len+2 );
+				if (skb == NULL) {
+					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
+						      dev->name ));
+					
+					lp->stats.rx_dropped++;
+					head->msg_length = 0;
+					head->flag |= RMD1_OWN_CHIP;
+					lp->new_rx = (lp->new_rx+1) &
+					     RX_RING_MOD_MASK;
+				}
+
+#if 0
+				if (lance_debug >= 3) {
+					u_char *data = PKTBUF_ADDR(head), *p;
+					printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]);
+					for( p = &data[6], i = 0; i < 6; i++ )
+						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					printk(" to ");
+					for( p = data, i = 0; i < 6; i++ )
+						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+					       "len %d at %08x\n",
+					       data[15], data[16], data[17], data[18],
+					       data[19], data[20], data[21], data[22],
+					       pkt_len, data);
+				}
+#endif
+				if (lance_debug >= 3) {
+					u_char *data = PKTBUF_ADDR(head);
+					printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len);
+				}				
+
+
+				skb->dev = dev;
+				skb_reserve( skb, 2 );	/* 16 byte align */
+				skb_put( skb, pkt_len );	/* Make room */
+//			        memcpy( skb->data, PKTBUF_ADDR(head), pkt_len );
+				eth_copy_and_sum(skb,
+						 PKTBUF_ADDR(head),
+						 pkt_len, 0);
+
+				skb->protocol = eth_type_trans( skb, dev );
+				netif_rx( skb );
+				lp->stats.rx_packets++;
+				lp->stats.rx_bytes += skb->len;
+			}
+		}
+
+//		head->buf_length = -PKT_BUF_SZ | 0xf000;
+		head->msg_length = 0;
+		head->flag = RMD1_OWN_CHIP;
+
+		entry = lp->new_rx = (lp->new_rx +1) & RX_RING_MOD_MASK;
+	}
+
+	/* From lance.c (Donald Becker): */
+	/* We should check that at least two ring entries are free.
+	   If not, we should free one and mark stats->rx_dropped++. */
+
+	return 0;
+}
+
+
+static int lance_close( struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	AREG = CSR0;
+
+	DPRINTK( 2, ( "%s: Shutting down ethercard, status was %2.2x.\n",
+				  dev->name, DREG ));
+
+	/* We stop the LANCE here -- it occasionally polls
+	   memory if we don't. */
+	DREG = CSR0_STOP;
+
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+
+static struct net_device_stats *lance_get_stats( struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+
+	return &lp->stats;
+}
+
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1		Promiscuous mode, receive all packets
+   num_addrs == 0		Normal mode, clear multicast list
+   num_addrs > 0		Multicast mode, receive normal and MC packets, and do
+						best-effort filtering.
+ */
+
+/* completely untested on a sun3 */
+static void set_multicast_list( struct net_device *dev )
+{
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+
+	if (!dev->start)
+		/* Only possible if board is already started */
+		return;
+
+	/* We take the simple way out and always enable promiscuous mode. */
+	DREG = CSR0_STOP; /* Temporarily stop the lance. */
+
+	if (dev->flags & IFF_PROMISC) {
+		/* Log any net taps. */
+		DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+		REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
+	} else {
+		short multicast_table[4];
+		int num_addrs = dev->mc_count;
+		int i;
+		/* We don't use the multicast table, but rely on upper-layer
+		 * filtering. */
+		memset( multicast_table, (num_addrs == 0) ? 0 : -1,
+				sizeof(multicast_table) );
+		for( i = 0; i < 4; i++ )
+			REGA( CSR8+i ) = multicast_table[i];
+		REGA( CSR15 ) = 0; /* Unset promiscuous mode */
+	}
+
+	/*
+	 * Always set BSWP after a STOP as STOP puts it back into
+	 * little endian mode.
+	 */
+	REGA( CSR3 ) = CSR3_BSWP;
+
+	/* Resume normal operation and reset AREG to CSR0 */
+	REGA( CSR0 ) = CSR0_IDON | CSR0_INEA | CSR0_STRT;
+}
+
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+
+static struct net_device sun3lance_dev =
+{
+	devicename,	/* filled in by register_netdev() */
+	0, 0, 0, 0,	/* memory */
+	0, 0,		/* base, irq */
+	0, 0, 0, NULL, sun3lance_probe,
+};
+
+int init_module(void)
+{
+	int err;
+
+	if ((err = register_netdev( &sun3lance_dev ))) {
+		if (err == -EIO)  {
+			printk( "SUN3 Lance not detected.  Module not loaded.\n");
+		}
+		return( err );
+	}
+	return( 0 );
+}
+
+void cleanup_module(void)
+{
+	unregister_netdev( &sun3lance_dev );
+}
+
+#endif /* MODULE */
+
diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/Makefile linux/drivers/nubus/Makefile
--- v2.3.16/linux/drivers/nubus/Makefile	Sat Mar 21 11:06:51 1998
+++ linux/drivers/nubus/Makefile	Sat Sep  4 13:08:32 1999
@@ -9,7 +9,19 @@
 # parent makefile.
 #
 
-L_OBJS   := nubus.o
 L_TARGET := nubus.a
+
+ifeq ($(CONFIG_MODULES),y)
+O_TARGET := nubus_n_syms.o
+OX_OBJS  := nubus_syms.o
+O_OBJS   := nubus.o
+L_OBJS   := nubus_n_syms.o
+else
+L_OBJS   := nubus.o
+endif
+
+ifdef CONFIG_PROC_FS
+L_OBJS   += proc.o
+endif
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/nubus.c linux/drivers/nubus/nubus.c
--- v2.3.16/linux/drivers/nubus/nubus.c	Tue Jul 20 16:40:30 1999
+++ linux/drivers/nubus/nubus.c	Sat Sep  4 13:08:32 1999
@@ -1,77 +1,120 @@
 /*
  *	Macintosh Nubus Interface Code
+ *
+ *      Originally by Alan Cox
+ *
+ *      Mostly rewritten by David Huggins-Daines, C. Scott Ananian,
+ *      and others.
  */
 
 #include <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/pci.h>
 #include <linux/string.h>
 #include <linux/nubus.h>
 #include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/hwtest.h>
-/* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */
-#include <asm/macintosh.h>
 #include <linux/proc_fs.h>
+#include <asm/mac_via.h>
+#include <asm/mac_oss.h>
 
+extern void via_nubus_init(void);
+extern void oss_nubus_init(void);
 
-#undef LCIII_WEIRDNESS
- 
-static struct nubus_slot nubus_slots[16];
- 
-/*
- *	Please skip to the bottom of this file if you ate lunch recently
- *				-- Alan
- */
- 
+extern int console_loglevel;
 
-/*
- *	Yes this sucks. The ROM can appear on arbitary bytes of the long
- *	word. We are not amused.
- */
+/* Constants */
+
+/* This is, of course, the size in bytelanes, rather than the size in
+   actual bytes */
+#define FORMAT_BLOCK_SIZE 20
+#define ROM_DIR_OFFSET 0x24
+
+#define NUBUS_TEST_PATTERN 0x5A932BC7
+
+/* Define this if you like to live dangerously - it is known not to
+   work on pretty much every machine except the Quadra 630 and the LC
+   III. */
+#undef I_WANT_TO_PROBE_SLOT_ZERO
+
+/* This sometimes helps combat failure to boot */
+#undef TRY_TO_DODGE_WSOD
+
+/* Globals */
+
+struct nubus_dev*   nubus_devices;
+struct nubus_board* nubus_boards;
+
+/* Meaning of "bytelanes":
+
+   The card ROM may appear on any or all bytes of each long word in
+   NuBus memory.  The low 4 bits of the "map" value found in the
+   format block (at the top of the slot address space, as well as at
+   the top of the MacOS ROM) tells us which bytelanes, i.e. which byte
+   offsets within each longword, are valid.  Thus:
+
+   A map of 0x0f, as found in the MacOS ROM, means that all bytelanes
+   are valid.
+
+   A map of 0xf0 means that no bytelanes are valid (We pray that we
+   will never encounter this, but stranger things have happened)
+
+   A map of 0xe1 means that only the MSB of each long word is actually
+   part of the card ROM.  (We hope to never encounter NuBus on a
+   little-endian machine.  Again, stranger things have happened)
+
+   A map of 0x78 means that only the LSB of each long word is valid.
+
+   Etcetera, etcetera.  Hopefully this clears up some confusion over
+   what the following code actually does.  */
  
-extern __inline__ int not_useful(void *p, int map)
+extern inline int not_useful(void *p, int map)
 {
 	unsigned long pv=(unsigned long)p;
-	pv&=3;
-	if(map&(1<<pv))
+	pv &= 3;
+	if(map & (1<<pv))
 		return 0;
 	return 1;
 }
  
 static unsigned long nubus_get_rom(unsigned char **ptr, int len, int map)
 {
-	unsigned long v=0;
-	unsigned char *p=*ptr;	/* as v|=*((*ptr)++) upset someone */
+	/* This will hold the result */
+	unsigned long v = 0;
+	unsigned char *p = *ptr;
+
 	while(len)
 	{
-		v<<=8;
+		v <<= 8;
 		while(not_useful(p,map))
 			p++;
-		v|=*p++;
+		v |= *p++;
 		len--;
 	}
-	*ptr=p;
+	*ptr = p;
 	return v;
 }
 
 static void nubus_rewind(unsigned char **ptr, int len, int map)
 {
 	unsigned char *p=*ptr;
-	
-	if(len>65536)
-		printk("rewind of %d!\n", len);
+
+	/* Sanity check */
+	if(len > 65536)
+		printk(KERN_ERR "rewind of 0x%08x!\n", len);
 	while(len)
 	{
 		do
 		{
 			p--;
 		}
-		while(not_useful(p,map));
+		while(not_useful(p, map));
 		len--;
 	}
 	*ptr=p;
@@ -79,9 +122,9 @@
 
 static void nubus_advance(unsigned char **ptr, int len, int map)
 {
-	unsigned char *p=*ptr;
+	unsigned char *p = *ptr;
 	if(len>65536)
-		printk("advance of %d!\n", len);
+		printk(KERN_ERR "advance of 0x%08x!\n", len);
 	while(len)
 	{
 		while(not_useful(p,map))
@@ -89,29 +132,32 @@
 			p++;
 		len--;
 	}
-	*ptr=p;
+	*ptr = p;
 }
 
-/*
- *	24bit signed offset to 32bit
- */
- 
-static unsigned long nubus_expand32(unsigned long foo)
+static void nubus_move(unsigned char **ptr, int len, int map)
 {
-	if(foo&0x00800000)	/* 24bit negative */
-		foo|=0xFF000000;
-	return foo;
+	if(len > 0)
+		nubus_advance(ptr, len, map);
+	else if(len < 0)
+		nubus_rewind(ptr, -len, map);
 }
 
-static void nubus_move(unsigned char **ptr, int len, int map)
+/* Now, functions to read the sResource tree */
+
+/* Each sResource entry consists of a 1-byte ID and a 3-byte data
+   field.  If that data field contains an offset, then obviously we
+   have to expand it from a 24-bit signed number to a 32-bit signed
+   number. */
+
+extern inline long nubus_expand32(long foo)
 {
-	if(len>0)
-		nubus_advance(ptr,len,map);
-	else if(len<0)
-		nubus_rewind(ptr,-len,map);
+	if(foo & 0x00800000)	/* 24bit negative */
+		foo |= 0xFF000000;
+	return foo;
 }
 
-static void *nubus_rom_addr(int slot)
+extern inline void *nubus_rom_addr(int slot)
 {	
 	/*
 	 *	Returns the first byte after the card. We then walk
@@ -120,472 +166,820 @@
 	return (void *)(0xF1000000+(slot<<24));
 }
 
-void nubus_memcpy(int slot, void *to, unsigned char *p, int len)
+static unsigned char *nubus_dirptr(const struct nubus_dirent *nd)
 {
-	unsigned char *t=(unsigned char *)to;
+	unsigned char *p = nd->base;
+	/* Essentially, just step over the bytelanes using whatever
+	   offset we might have found */
+	nubus_move(&p, nubus_expand32(nd->data), nd->mask);
+	/* And return the value */
+	return p;
+}
+
+/* These two are for pulling resource data blocks (i.e. stuff that's
+   pointed to with offsets) out of the card ROM. */
+
+void nubus_get_rsrc_mem(void *dest, const struct nubus_dirent* dirent,
+			int len)
+{
+	unsigned char *t = (unsigned char *)dest;
+	unsigned char *p = nubus_dirptr(dirent);
 	while(len)
 	{
-		*t++=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes);
+		*t++ = nubus_get_rom(&p, 1, dirent->mask);
 		len--;
 	}
 }
 
-void nubus_strncpy(int slot, void *to, unsigned char *p, int len)
+void nubus_get_rsrc_str(void *dest, const struct nubus_dirent* dirent,
+			int len)
 {
-	unsigned char *t=(unsigned char *)to;
+	unsigned char *t=(unsigned char *)dest;
+	unsigned char *p = nubus_dirptr(dirent);
 	while(len)
 	{
-		*t=nubus_get_rom(&p,1, nubus_slots[slot].slot_lanes);
+		*t = nubus_get_rom(&p, 1, dirent->mask);
 		if(!*t++)
 			break;
 		len--;
 	}
 }
 
-
-
-	
-unsigned char *nubus_dirptr(struct nubus_dirent *nd)
+int nubus_get_root_dir(const struct nubus_board* board,
+		       struct nubus_dir* dir)
 {
-	unsigned char *p=(unsigned char *)(nd->base);
-	
-	nubus_move(&p, nubus_expand32(nd->value), nd->mask);
-	return p;
+	dir->ptr = dir->base = board->directory;
+	dir->done = 0;
+	dir->mask = board->lanes;
+	return 0;
 }
 
-	
-struct nubus_dir *nubus_openrootdir(int slot)
-{
-	static struct nubus_dir nbdir;
-	unsigned char *rp=nubus_rom_addr(slot);
-	
-	nubus_rewind(&rp,20, nubus_slots[slot].slot_lanes);
-
-	nubus_move(&rp, nubus_expand32(nubus_slots[slot].slot_directory),
-		nubus_slots[slot].slot_lanes);
-		
-	nbdir.base=rp;
-	nbdir.length=nubus_slots[slot].slot_dlength;
-	nbdir.count=0;
-	nbdir.mask=nubus_slots[slot].slot_lanes;
-	return &nbdir;
+/* This is a slyly renamed version of the above */
+int nubus_get_func_dir(const struct nubus_dev* dev,
+		       struct nubus_dir* dir)
+{
+	dir->ptr = dir->base = dev->directory;
+	dir->done = 0;
+	dir->mask = dev->board->lanes;
+	return 0;
 }
 
-struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d)
+int nubus_get_board_dir(const struct nubus_board* board,
+			struct nubus_dir* dir)
 {
-	static struct nubus_dir nbdir;
-	unsigned char *rp=nubus_dirptr(d);
-	nbdir.base=rp;
-	nbdir.length=99999;/*slots[i].slot_dlength;*/
-	nbdir.count=0;
-	nbdir.mask=d->mask;
-	return &nbdir;
+	struct nubus_dirent ent;
+	
+	dir->ptr = dir->base = board->directory;
+	dir->done = 0;
+	dir->mask = board->lanes;
+
+	/* Now dereference it (the first directory is always the board
+	   directory) */
+	if (nubus_readdir(dir, &ent) == -1)
+		return -1;
+	if (nubus_get_subdir(&ent, dir) == -1)
+		return -1;
+	return 0;
 }
 
-void nubus_closedir(struct nubus_dir *nd)
+int nubus_get_subdir(const struct nubus_dirent *ent,
+		     struct nubus_dir *dir)
 {
-	;
+	dir->ptr = dir->base = nubus_dirptr(ent);
+	dir->done = 0;
+	dir->mask = ent->mask;
+	return 0;
 }
 
-struct nubus_dirent *nubus_readdir(struct nubus_dir *nd)
+int nubus_readdir(struct nubus_dir *nd, struct nubus_dirent *ent)
 {
 	u32 resid;
-	u8 rescode;
-	static struct nubus_dirent d;
-	
-	if(nd->count==nd->length)
-		return NULL;
+	if (nd->done)
+		return -1;
 
-	d.base=(unsigned long)nd->base;
-		
-	resid=nubus_get_rom(&nd->base, 4, nd->mask);
-	nd->count++;
-	rescode=resid>>24;
-	if(rescode==0xFF)
-	{
-		nd->count=nd->length;
-		return NULL;
-	}
-	d.type=rescode;
-	d.value=resid&0xFFFFFF;
-	d.mask=nd->mask;
-	return &d;
-}
+	/* Do this first, otherwise nubus_rewind & co are off by 4 */
+	ent->base = nd->ptr;
 
-/*
- *	MAC video handling irritations
- */
+	/* This moves nd->ptr forward */
+	resid = nubus_get_rom(&nd->ptr, 4, nd->mask);
 
-static unsigned char nubus_vid_byte[16];
-static unsigned long nubus_vid_offset[16];
+	/* EOL marker, as per the Apple docs */
+	if((resid&0xff000000) == 0xff000000)
+	{
+		/* Mark it as done */
+		nd->done = 1;
+		return -1;
+	}
 
-static void nubus_irqsplat(int slot, void *dev_id, struct pt_regs *regs)
-{
-	unsigned char *p=((unsigned char *)nubus_slot_addr(slot))+
-			nubus_vid_offset[slot];
-	*p=nubus_vid_byte[slot];
+	/* First byte is the resource ID */
+	ent->type  = resid >> 24;
+	/* Low 3 bytes might contain data (or might not) */
+	ent->data = resid & 0xffffff;
+	ent->mask  = nd->mask;
+	return 0;
 }
 
-static int nubus_add_irqsplatter(int slot, unsigned long ptr, unsigned char v)
+int nubus_rewinddir(struct nubus_dir* dir)
 {
-	nubus_vid_byte[slot]=v;
-	nubus_vid_offset[slot]=ptr;
-	nubus_request_irq(slot, NULL, nubus_irqsplat);
+	dir->ptr = dir->base;
 	return 0;
 }
- 
-void nubus_video_shutup(int slot, struct nubus_type *nt)
-{
-	if(nt->category!=3 /* Display */ || nt->type!=1 /* Video */
-		|| nt->DrSW!=1 /* Quickdraw device */)
-		return;
-	switch(nt->DrHW)
-	{
-		/*
-		 *	Toby and MacII Hires cards. These behave in a MacII
-		 *	anyway but not on an RBV box
-		 */
-		case 0x0001:
-		case 0x0013:
-			nubus_add_irqsplatter(slot, 0xA0000, 0);
-			break;
-		/*
-		 *	Apple workstation video card.
-		 */
-		case 0x0006:
-			nubus_add_irqsplatter(slot, 0xA00000, 0);
-			break;
-		/*
-		 *	Futura cards
-		 */
-		case 0x0417:
-		case 0x042F:
-			nubus_add_irqsplatter(slot, 0xF05000, 0x80);
-			break;
-			
-		/*
-		 *	Fingers crossed 8)
-		 *	
-		 *	If you have another card and an RBV based mac you'll
-		 *	almost certainly have to add it here to make it work.
-		 */
-		
-		default:
-			break;
+
+/* Driver interface functions, more or less like in pci.c */
+
+struct nubus_dev*
+nubus_find_device(unsigned short category,
+		  unsigned short type,
+		  unsigned short dr_hw,
+		  unsigned short dr_sw,
+		  const struct nubus_dev* from)
+{
+	struct nubus_dev* itor =
+		from ? from->next : nubus_devices;
+
+	while (itor) {
+		if (itor->category == category
+		    && itor->type == type
+		    && itor->dr_hw == dr_hw
+		    && itor->dr_sw == dr_sw)
+			return itor;
+		itor = itor->next;
 	}
+	return NULL;
 }
 
-/*
- *	Device list
- */
+struct nubus_dev*
+nubus_find_type(unsigned short category,
+		unsigned short type,
+		const struct nubus_dev* from)
+{
+	struct nubus_dev* itor =
+		from ? from->next : nubus_devices;
+
+	while (itor) {
+		if (itor->category == category
+		    && itor->type == type)
+			return itor;
+		itor = itor->next;
+	}
+	return NULL;
+}
 
-static struct nubus_device_specifier *nubus_device_list=NULL;
- 
-void register_nubus_device(struct nubus_device_specifier *d)
+struct nubus_dev*
+nubus_find_slot(unsigned int slot,
+		const struct nubus_dev* from)
 {
-	d->next=nubus_device_list;
-	nubus_device_list=d;
+	struct nubus_dev* itor =
+		from ? from->next : nubus_devices;
+	
+	while (itor) {
+		if (itor->board->slot == slot)
+			return itor;
+		itor = itor->next;
+	}
+	return NULL;
 }
 
-void unregister_nubus_device(struct nubus_device_specifier *nb)
-{
-	struct nubus_device_specifier **t=&nubus_device_list;
-	while(*t!=nb && *t)
-		t=&((*t)->next);
-	*t=nb->next;
+int
+nubus_find_rsrc(struct nubus_dir* dir, unsigned char rsrc_type,
+		struct nubus_dirent* ent)
+{
+	while (nubus_readdir(dir, ent) != -1) {
+		if (ent->type == rsrc_type)
+			return 0;
+	}	
+	return -1;
+}
+
+/* Initialization functions - decide which slots contain stuff worth
+   looking at, and print out lots and lots of information from the
+   resource blocks. */
+
+/* FIXME: A lot of this stuff will eventually be useful after
+   initializaton, for intelligently probing Ethernet and video chips,
+   among other things.  The rest of it should go in the /proc code.
+   For now, we just use it to give verbose boot logs. */
+
+static int __init nubus_show_display_resource(struct nubus_dev* dev,
+					      const struct nubus_dirent* ent)
+{
+	switch (ent->type) {
+	case NUBUS_RESID_GAMMADIR:
+		printk(KERN_INFO "    gamma directory offset: 0x%06x\n", ent->data);
+		break;
+	case 0x0080 ... 0x0085:
+		printk(KERN_INFO "    mode %02X info offset: 0x%06x\n",
+		       ent->type, ent->data);
+		break;
+	default:
+		printk(KERN_INFO "    unknown resource %02X, data 0x%06x\n",
+		       ent->type, ent->data);
+	}
+	return 0;
 }
 
-static struct nubus_device_specifier *find_nubus_device(int slot, struct nubus_type *nt)
+static int __init nubus_show_network_resource(struct nubus_dev* dev,
+					      const struct nubus_dirent* ent)
 {
-	struct nubus_device_specifier *t=nubus_device_list; 
-	while(t!=NULL)
+	switch (ent->type) {
+	case NUBUS_RESID_MAC_ADDRESS:
 	{
-		if(t->setup(t,slot, nt)==0)
-			return t;
-		t=t->next;
+		char addr[6];
+		int i;
+		
+		nubus_get_rsrc_mem(addr, ent, 6);
+		printk(KERN_INFO "    MAC address: ");
+		for (i = 0; i < 6; i++)
+			printk("%02x%s", addr[i] & 0xff,
+			       i == 5 ? "" : ":");
+		printk("\n");
+		break;
 	}
-	printk("No driver for device [%d %d %d %d]\n",
-		nt->category, nt->type, nt->DrHW, nt->DrSW);
-	return NULL;
+	default:
+		printk(KERN_INFO "    unknown resource %02X, data 0x%06x\n",
+		       ent->type, ent->data);
+	}
+	return 0;
 }
 
-/*
- *	Probe a nubus slot
- */
+static int __init nubus_show_cpu_resource(struct nubus_dev* dev,
+					  const struct nubus_dirent* ent)
+{
+	switch (ent->type) {
+	case NUBUS_RESID_MEMINFO:
+	{
+		unsigned long meminfo[2];
+		nubus_get_rsrc_mem(&meminfo, ent, 8);
+		printk(KERN_INFO "    memory: [ 0x%08lx 0x%08lx ]\n",
+		       meminfo[0], meminfo[1]);
+		break;
+	}
+	case NUBUS_RESID_ROMINFO:
+	{
+		unsigned long rominfo[2];
+		nubus_get_rsrc_mem(&rominfo, ent, 8);
+		printk(KERN_INFO "    ROM:    [ 0x%08lx 0x%08lx ]\n",
+		       rominfo[0], rominfo[1]);
+		break;
+	}
+	default:
+		printk(KERN_INFO "    unknown resource %02X, data 0x%06x\n",
+		       ent->type, ent->data);
+	}
+	return 0;
+}
 
-void nubus_probe_slot(int slot, int mode)
+static int __init nubus_show_private_resource(struct nubus_dev* dev,
+					      const struct nubus_dirent* ent)
 {
-	unsigned char *rp;
-	unsigned char dp;
-	int lanes;
-	int i;
-	unsigned long dpat;
-	struct nubus_dir *dir;
-	struct nubus_dirent *nd;
-	struct nubus_type type_info;
+	switch (dev->category) {
+	case NUBUS_CAT_DISPLAY:
+		nubus_show_display_resource(dev, ent);
+		break;
+	case NUBUS_CAT_NETWORK:
+		nubus_show_network_resource(dev, ent);
+		break;
+	case NUBUS_CAT_CPU:
+		nubus_show_cpu_resource(dev, ent);
+		break;
+	default:
+		printk(KERN_INFO "    unknown resource %02X, data 0x%06x\n",
+		       ent->type, ent->data);
+	}
+	return 0;
+}
 
-	/*
-	 *	Ok see whats cooking in the bytelanes
-	 */
+static struct nubus_dev* __init
+	   nubus_get_functional_resource(struct nubus_board* board,
+					 int slot,
+					 const struct nubus_dirent* parent)
+{
+	struct nubus_dir    dir;
+	struct nubus_dirent ent;
+	struct nubus_dev*   dev;
 	
-	rp=nubus_rom_addr(slot);
+	printk(KERN_INFO "  Function 0x%02x:\n", parent->type);
+	nubus_get_subdir(parent, &dir);
+
+	/* Apple seems to have botched the ROM on the IIx */
+	if (slot == 0 && (unsigned long)dir.base % 2)
+		dir.base += 1;
 	
-	for(i=4;i;i--)
-	{
-		rp--;
-		
-		if(!hwreg_present(rp))
-			continue;
-			
-		dp=*rp;
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_functional_resource: parent is 0x%p, dir is 0x%p\n",
+		       parent->base, dir.base);
+
+	/* Actually we should probably panic if this fails */
+	if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
+		return NULL;	
+	memset(dev, 0, sizeof(*dev));
+	dev->resid = parent->type;
+	dev->directory = dir.base;
+	dev->board = board;
 	
-		if(dp==0)
-			continue;
-		
-		/*
-		 *	Valid ?
-		 */
-		 
-		if((((dp>>4)^dp)&0x0F)!=0x0F)
-			continue;
-			
-		if((dp&0x0F) >= 1<<i)
-			continue;
-			
-		/*
-		 *	Looks promising
-		 */
-		
-		nubus_slots[slot].slot_flags|=NUBUS_DEVICE_PRESENT;
-		lanes=dp;
-
-		if (mode==0)
-			printk("nubus%c: ",
-				"0123456789abcdef"[slot]);
-		
-		
-		/*
-		 *	Time to dig deeper. Find the ROM base
-		 *	and read it
-		 */
-		 
-		rp=nubus_rom_addr(slot); 
-		
-		/*
-		 *	Now to make this more fun the ROM is only visible
-		 *	on its bytelanes - that is smeared across the address
-		 *	space.
-		 */
-		
-		nubus_rewind(&rp,20,lanes);
-		
-		nubus_slots[slot].slot_directory=	nubus_get_rom(&rp,4,lanes);
-		nubus_slots[slot].slot_dlength	=	nubus_get_rom(&rp,4,lanes);
-		nubus_slots[slot].slot_crc	=	nubus_get_rom(&rp,4,lanes);
-		nubus_slots[slot].slot_rev	=	nubus_get_rom(&rp,1,lanes);
-		nubus_slots[slot].slot_format	=	nubus_get_rom(&rp,1,lanes);
-		nubus_slots[slot].slot_lanes	=	lanes;
-		
-		dpat=nubus_get_rom(&rp,4,lanes);
-		
-		/*
-		 *	Ok now check what we got
-		 */
-		
-		if(!(nubus_slots[slot].slot_directory&0x00FF0000))
-			printk("Dodgy doffset ??\n");
-		if(dpat!=0x5A932BC7)
-			printk("Wrong test pattern %lx\n",dpat);
-		
-		/*
-		 *	I wonder how the CRC is meant to work -
-		 *		any takers ?
-		 */
-		
-		
-		/*
-		 *	Now parse the directories on the card
-		 */
-		 
-		
-		dir=nubus_openrootdir(slot);
-		
-		/*
-		 *	Find the board resource
-		 */
-		 
-		while((nd=nubus_readdir(dir))!=NULL)
+	while (nubus_readdir(&dir, &ent) != -1)
+	{
+		switch(ent.type)
 		{
-			/*
-			 *	This ought to be 1. 1 doesn't work, 0x80
-			 *	does. Seems the Apple docs are wrong.
-			 */
-			if(nd->type==0x80/*RES_ID_BOARD_DIR*/)
-				break;
+		case NUBUS_RESID_TYPE:
+		{
+			unsigned short nbtdata[4];
+			nubus_get_rsrc_mem(nbtdata, &ent, 8);
+			dev->category = nbtdata[0];
+			dev->type     = nbtdata[1];
+			dev->dr_sw    = nbtdata[2];
+			dev->dr_hw    = nbtdata[3];
+			printk(KERN_INFO "    type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n",
+			       nbtdata[0], nbtdata[1], nbtdata[2], nbtdata[3]);
+			break;
 		}
-		
-		nubus_closedir(dir);
-		
-		if(nd==NULL)
+		case NUBUS_RESID_NAME:
 		{
-			printk("board resource not found!\n");
-			return;
+			nubus_get_rsrc_str(dev->name, &ent, 64);
+			printk(KERN_INFO "    name: %s\n", dev->name);
+			break;
 		}
-		
-		dir=nubus_opensubdir(nd);
-				
-		/*
-		 *	Walk the board resource
-		 */
-		 
-		while((nd=nubus_readdir(dir))!=NULL)
+		case NUBUS_RESID_DRVRDIR:
 		{
-			switch(nd->type)
-			{
-				case RES_ID_TYPE:
-				{
-					unsigned short nbtdata[4];
-					nubus_memcpy(slot, nbtdata, nubus_dirptr(nd), 8);
-					type_info.category=nbtdata[0];
-					type_info.type=nbtdata[1];
-					type_info.DrHW=nbtdata[2];
-					type_info.DrSW=nbtdata[3];
-					break;
-				}
-				case RES_ID_NAME:
-					nubus_strncpy(slot, nubus_slots[slot].slot_cardname,nubus_dirptr(nd),64);
-					break;
-				default:
-					;
-			}
+			/* MacOS driver.  If we were NetBSD we might
+			   use this :-) */
+			struct nubus_dir drvr_dir;
+			struct nubus_dirent drvr_ent;
+			nubus_get_subdir(&ent, &drvr_dir);
+			nubus_readdir(&drvr_dir, &drvr_ent);
+			dev->driver = nubus_dirptr(&drvr_ent);
+			printk(KERN_INFO "    driver at: 0x%p\n",
+			       dev->driver);
+			break;
 		}
-		
-		nubus_closedir(dir);
-
-		/*
-		 *	Attempt to bind a driver to this slot
-		 */
-		
-		if (mode==0) {
-			printk("%s\n",
-				nubus_slots[slot].slot_cardname);
-			find_nubus_device(slot,&type_info);
+		case NUBUS_RESID_MINOR_BASEOS:
+			/* We will need this in order to support
+			   multiple framebuffers.  It might be handy
+			   for Ethernet as well */
+			nubus_get_rsrc_mem(&dev->iobase, &ent, 4);
+			printk(KERN_INFO "    memory offset: 0x%08lx\n",
+			       dev->iobase);
+			break;
+		case NUBUS_RESID_MINOR_LENGTH:
+			/* Ditto */
+			nubus_get_rsrc_mem(&dev->iosize, &ent, 4);
+			printk(KERN_INFO "    memory length: 0x%08lx\n",
+			       dev->iosize);
+			break;			
+		case NUBUS_RESID_FLAGS:
+			dev->flags = ent.data;
+			printk(KERN_INFO "    flags: 0x%06x\n", dev->flags);
+			break;
+		case NUBUS_RESID_HWDEVID:
+			dev->hwdevid = ent.data;
+			printk(KERN_INFO "    hwdevid: 0x%06x\n", dev->hwdevid);
+			break;
+		default:
+			/* Local/Private resources have their own
+			   function */
+			nubus_show_private_resource(dev, &ent);
 		}
-		if (mode==1)
-			nubus_video_shutup(slot, &type_info);
-
-		return;
 	}
+		
+	return dev;
 }
 
+/* This is cool. */
+static int __init nubus_get_vidnames(struct nubus_board* board,
+				     const struct nubus_dirent* parent)
+{
+	struct nubus_dir    dir;
+	struct nubus_dirent ent;
+	/* FIXME: obviously we want to put this in a header file soon */
+	struct vidmode {
+		u32 size;
+		/* Don't know what this is yet */
+		u16 id;
+		/* Longest one I've seen so far is 26 characters */
+		char name[32];
+	};
+
+	printk(KERN_INFO "    video modes supported:\n");
+	nubus_get_subdir(parent, &dir);
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_vidnames: parent is 0x%p, dir is 0x%p\n",
+		       parent->base, dir.base);
 
-void nubus_probe_bus(void)
-{
-	int i;
-	for(i=9;i<15;i++)
+	while(nubus_readdir(&dir, &ent) != -1)
 	{
-		/* printk("nubus: probing slot %d !\n", i); */
-		nubus_probe_slot(i, 0);
+		struct vidmode mode;
+		u32 size;
+
+		/* First get the length */
+		nubus_get_rsrc_mem(&size, &ent, 4);
+		
+		/* Now clobber the whole thing */
+		if (size > sizeof(mode) - 1)
+			size = sizeof(mode) - 1;
+		memset(&mode, sizeof(mode), 0);
+		nubus_get_rsrc_mem(&mode, &ent, size);
+		printk (KERN_INFO "      %02X: (%02X) %s\n", ent.type,
+			mode.id, mode.name);
 	}
+	return 0;
 }
 
-/*
- *	RBV machines have level triggered video interrupts, and a VIA
- *	emulation that doesn't always seem to include being able to disable 
- *	an interrupt. Totally lusing hardware. Before we can init irq's we
- *	have to install a handler to shut the bloody things up.
- */
+/* This is *really* cool. */
+static int __init nubus_get_icon(struct nubus_board* board,
+				 const struct nubus_dirent* ent)
+{
+	/* Should be 32x32 if my memory serves me correctly */
+	unsigned char icon[128];
+	int x, y;
+	
+	nubus_get_rsrc_mem(&icon, ent, 128);
+	printk(KERN_INFO "    icon:\n");
 
-void nubus_sweep_video(void)
+	/* We should actually plot these somewhere in the framebuffer
+	   init.  This is just to demonstrate that they do, in fact,
+	   exist */
+	for (y = 0; y < 32; y++) {
+		printk(KERN_INFO "      ");
+		for (x = 0; x < 32; x++) {
+			if (icon[y*4 + x/8]
+			    & (0x80 >> (x%8)))
+				printk("*");
+			else
+				printk(" ");
+		}
+		printk("\n");
+	}
+	return 0;
+}
+
+static int __init nubus_get_vendorinfo(struct nubus_board* board,
+				       const struct nubus_dirent* parent)
 {
-	int i;
-	return; /* XXX why ?? */
-	for(i=9;i<15;i++)
+	struct nubus_dir    dir;
+	struct nubus_dirent ent;
+	static char* vendor_fields[6] = {"ID", "serial", "revision",
+					 "part", "date", "unknown field"};
+
+	printk(KERN_INFO "    vendor info:\n");
+	nubus_get_subdir(parent, &dir);
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_vendorinfo: parent is 0x%p, dir is 0x%p\n",
+		       parent->base, dir.base);
+
+	while(nubus_readdir(&dir, &ent) != -1)
 	{
-		nubus_probe_slot(i,1);
+		char name[64];
+		
+		/* These are all strings, we think */
+		nubus_get_rsrc_str(name, &ent, 64);
+		if (ent.type > 5)
+			ent.type = 5;
+		printk(KERN_INFO "    %s: %s\n",
+		       vendor_fields[ent.type-1], name);
 	}
+	return 0;
 }
 
-/*
- *	Support functions
- */
- 
-int nubus_ethernet_addr(int slot, unsigned char *addr)
+static int __init nubus_get_board_resource(struct nubus_board* board, int slot,
+					   const struct nubus_dirent* parent)
 {
-	struct nubus_dir *nb;
-	struct nubus_dirent *d;
-	int ng=-ENOENT;
-		
-	nb=nubus_openrootdir(slot);
+	struct nubus_dir    dir;
+	struct nubus_dirent ent;
 	
-	if(nb==NULL)
-		return -ENOENT;
-		
-	while((d=nubus_readdir(nb))!=NULL)
+	nubus_get_subdir(parent, &dir);
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_board_resource: parent is 0x%p, dir is 0x%p\n",
+		       parent->base, dir.base);
+
+	while(nubus_readdir(&dir, &ent) != -1)
 	{
-		if(d->type==0x80)	/* First private resource */
+		switch (ent.type) {
+		case NUBUS_RESID_TYPE:
+		{
+			unsigned short nbtdata[4];
+			/* This type is always the same, and is not
+			   useful except insofar as it tells us that
+			   we really are looking at a board resource. */
+			nubus_get_rsrc_mem(nbtdata, &ent, 8);
+			printk(KERN_INFO "    type: [cat 0x%x type 0x%x hw 0x%x sw 0x%x]\n",
+			       nbtdata[0], nbtdata[1], nbtdata[2],
+			       nbtdata[3]);
+			if (nbtdata[0] != 1 || nbtdata[1] != 0 ||
+			    nbtdata[2] != 0 || nbtdata[3] != 0)
+				printk(KERN_ERR "this sResource is not a board resource!\n");
+			break;
+		}
+		case NUBUS_RESID_NAME:
+			nubus_get_rsrc_str(board->name, &ent, 64);
+			printk(KERN_INFO "    name: %s\n", board->name);
+			break;
+		case NUBUS_RESID_ICON:
+			nubus_get_icon(board, &ent);
 			break;
+		case NUBUS_RESID_BOARDID:
+			printk(KERN_INFO "    board id: 0x%x\n", ent.data);
+			break;
+		case NUBUS_RESID_PRIMARYINIT:
+			printk(KERN_INFO "    primary init offset: 0x%06x\n", ent.data);
+			break;
+		case NUBUS_RESID_VENDORINFO:
+			nubus_get_vendorinfo(board, &ent);
+			break;
+		case NUBUS_RESID_FLAGS:
+			printk(KERN_INFO "    flags: 0x%06x\n", ent.data);
+			break;
+		case NUBUS_RESID_HWDEVID:
+			printk(KERN_INFO "    hwdevid: 0x%06x\n", ent.data);
+			break;
+		case NUBUS_RESID_SECONDINIT:
+			printk(KERN_INFO "    secondary init offset: 0x%06x\n", ent.data);
+			break;
+			/* WTF isn't this in the functional resources? */ 
+		case NUBUS_RESID_VIDNAMES:
+			nubus_get_vidnames(board, &ent);
+			break;
+			/* Same goes for this */
+		case NUBUS_RESID_VIDMODES:
+			printk(KERN_INFO "    video mode parameter directory offset: 0x%06x\n",
+			       ent.data);
+			break;			
+		default:
+			printk(KERN_INFO "    unknown resource %02X, data 0x%06x\n",
+			       ent.type, ent.data);
+		}
+	}
+	return 0;
+}
+
+/* Attempt to bypass the somewhat non-obvious arrangement of
+   sResources in the motherboard ROM */
+static void __init nubus_find_rom_dir(struct nubus_board* board)
+{
+	unsigned char* rp;
+	unsigned char* romdir;
+	struct nubus_dir dir;
+	struct nubus_dirent ent;
+
+	/* Check for the extra directory just under the format block */
+	rp = board->fblock;
+	nubus_rewind(&rp, 4, board->lanes);
+	if (nubus_get_rom(&rp, 4, board->lanes) != NUBUS_TEST_PATTERN) {
+		/* OK, the ROM was telling the truth */
+		board->directory = board->fblock;
+		nubus_move(&board->directory,
+			   nubus_expand32(board->doffset),
+			   board->lanes);
+		return;
 	}
-	if(d==NULL)
-		return -ENOENT;
+
+	/* On "slot zero", you have to walk down a few more
+	   directories to get to the equivalent of a real card's root
+	   directory.  We don't know what they were smoking when they
+	   came up with this. */
+	romdir = nubus_rom_addr(board->slot);
+	nubus_rewind(&romdir, ROM_DIR_OFFSET, board->lanes);
+	dir.base = dir.ptr = romdir;
+	dir.done = 0;
+	dir.mask = board->lanes;
+
+	/* This one points to an "Unknown Macintosh" directory */
+	if (nubus_readdir(&dir, &ent) == -1)
+		goto badrom;
+
+	if (console_loglevel >= 10)
+		printk(KERN_INFO "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
+	/* This one takes us to where we want to go. */
+	if (nubus_readdir(&dir, &ent) == -1) 
+		goto badrom;
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
+	nubus_get_subdir(&ent, &dir);
+
+	/* Resource ID 01, also an "Unknown Macintosh" */
+	if (nubus_readdir(&dir, &ent) == -1) 
+		goto badrom;
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
+
+	/* FIXME: the first one is *not* always the right one.  We
+	   suspect this has something to do with the ROM revision.
+	   "The HORROR ROM" (LC-series) uses 0x7e, while "The HORROR
+	   Continues" (Q630) uses 0x7b.  The DAFB Macs evidently use
+	   something else.  Please run "Slots" on your Mac (see
+	   include/linux/nubus.h for where to get this program) and
+	   tell us where the 'SiDirPtr' for Slot 0 is.  If you feel
+	   brave, you should also use MacsBug to walk down the ROM
+	   directories like this function does and try to find the
+	   path to that address... */
+	if (nubus_readdir(&dir, &ent) == -1)
+		goto badrom;
+	if (console_loglevel >= 10)
+		printk(KERN_DEBUG "nubus_get_rom_dir: entry %02x %06x\n", ent.type, ent.data);
 	
-	nb=nubus_opensubdir(d);
+	/* Bwahahahaha... */
+	nubus_get_subdir(&ent, &dir);
+	board->directory = dir.base;
+	return;
 	
-	while((d=nubus_readdir(nb))!=NULL)
-	{
-		if(d->type==0x80)	/* First private field is the mac */
-		{
-			int i;
-			nubus_memcpy(slot, addr, nubus_dirptr(d), 6);
-/*			printk("d.base=%lX, d.value=%lX\n",
-				d->base,d->value);
-			memcpy(addr,"\xC0\xC1\xC2\xC3\xC4\xC5",6);*/
-			printk("MAC address: ");
-			for(i=0;i<6;i++)
-			{
-				printk("%s%02X", i?":":"", addr[i]);
-			}
-			ng=0;
-			break;
+	/* Even more evil laughter... */
+ badrom:
+	board->directory = board->fblock;
+	nubus_move(&board->directory, nubus_expand32(board->doffset), board->lanes);
+	printk(KERN_ERR "nubus_get_rom_dir: ROM weirdness!  Notify the developers...\n");
+}
+
+/* Add a board (might be many devices) to the list */
+static struct nubus_board* __init nubus_add_board(int slot, int bytelanes)
+{
+	struct nubus_board* board;
+	struct nubus_board** boardp;
+
+	unsigned char *rp;
+	unsigned long dpat;
+	struct nubus_dir dir;
+	struct nubus_dirent ent;
+
+	/* Move to the start of the format block */
+	rp = nubus_rom_addr(slot);		
+	nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
+
+	/* Actually we should probably panic if this fails */
+	if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
+		return NULL;	
+	memset(board, 0, sizeof(*board));
+	board->fblock = rp;
+
+	/* Dump the format block for debugging purposes */
+	if (console_loglevel >= 10) {
+		int i;
+		printk(KERN_DEBUG "Slot %X, format block at 0x%p\n",
+		       slot, rp);
+		printk(KERN_DEBUG "Format block: ");
+		for (i = 0; i < FORMAT_BLOCK_SIZE; i += 4) {
+			unsigned short foo, bar;
+			foo = nubus_get_rom(&rp, 2, bytelanes);
+			bar = nubus_get_rom(&rp, 2, bytelanes);
+			printk("%04x %04x  ", foo, bar);
 		}
-		else
-			printk("ID=%d val=%x\n",
-				d->type, d->value);
+		printk("\n");
+		rp = board->fblock;
+	}
+	
+	board->slot = slot;
+	board->slot_addr = (unsigned long) nubus_slot_addr(slot);
+	board->doffset = nubus_get_rom(&rp, 4, bytelanes);
+	/* rom_length is *supposed* to be the total length of the
+	 * ROM.  In practice it is the "amount of ROM used to compute
+	 * the CRC."  So some jokers decide to set it to zero and
+	 * set the crc to zero so they don't have to do any math.
+	 * See the Performa 460 ROM, for example.  Those Apple "engineers".
+	 */
+	board->rom_length = nubus_get_rom(&rp, 4, bytelanes);
+	board->crc = nubus_get_rom(&rp, 4, bytelanes);
+	board->rev = nubus_get_rom(&rp, 1, bytelanes);
+	board->format = nubus_get_rom(&rp,1, bytelanes);
+	board->lanes = bytelanes;
+
+	/* Directory offset should be small and negative... */
+	if(!(board->doffset & 0x00FF0000))
+		printk(KERN_WARNING "Dodgy doffset!\n");
+	dpat = nubus_get_rom(&rp, 4, bytelanes);
+	if(dpat != NUBUS_TEST_PATTERN)
+		printk(KERN_WARNING "Wrong test pattern %08lx!\n", dpat);
+		
+	/*
+	 *	I wonder how the CRC is meant to work -
+	 *		any takers ?
+	 * CSA: According to MAC docs, not all cards pass the CRC anyway,
+	 * since the initial Macintosh ROM releases skipped the check.
+	 */
+
+	/* Attempt to work around slot zero weirdness */
+	nubus_find_rom_dir(board);
+	nubus_get_root_dir(board, &dir);	
+
+	/* We're ready to rock */
+	printk(KERN_INFO "Slot %X:\n", slot);
+
+	/* Each slot should have one board resource and any number of
+	   functional resources.  So we'll fill in some fields in the
+	   struct nubus_board from the board resource, then walk down
+	   the list of functional resources, spinning out a nubus_dev
+	   for each of them. */
+	if (nubus_readdir(&dir, &ent) == -1) {
+		/* We can't have this! */
+		printk(KERN_ERR "Board resource not found!\n");
+		return NULL;
+	} else {
+		printk(KERN_INFO "  Board resource:\n");
+		nubus_get_board_resource(board, slot, &ent);
+	}
+
+	/* Aaaarrrrgghh!  The LC III motherboard has *two* board
+	   resources.  I have no idea WTF to do about this. */
+
+	while (nubus_readdir(&dir, &ent) != -1) {
+		struct nubus_dev*  dev;
+		struct nubus_dev** devp;
+		dev = nubus_get_functional_resource(board, slot, &ent);
+		if (dev == NULL)
+			continue;
+
+		/* We zeroed this out above */
+		if (board->first_dev == NULL)
+			board->first_dev = dev;
+		
+		/* Put it on the global NuBus device chain. Keep entries in order. */
+		for (devp=&nubus_devices; *devp!=NULL; devp=&((*devp)->next))
+			/* spin */;
+		*devp = dev;
+		dev->next = NULL;		
 	}
-	return ng;
+
+	/* Put it on the global NuBus board chain. Keep entries in order. */
+	for (boardp=&nubus_boards; *boardp!=NULL; boardp=&((*boardp)->next))
+		/* spin */;
+	*boardp = board;
+	board->next = NULL;
+	
+	return board;
 }
 
-#ifdef CONFIG_PROC_FS
+void __init nubus_probe_slot(int slot)
+{
+	unsigned char dp;
+	unsigned char* rp;
+	int i;
 
-/*
- *	/proc for Nubus devices
- */
- 
-static int sprint_nubus_config(int slot, char *ptr, int len)
+	rp = nubus_rom_addr(slot);	
+	for(i = 4; i; i--)
+	{
+		unsigned long flags;
+		int card_present;
+
+		rp--;
+		save_flags(flags);
+		cli();
+		card_present = hwreg_present(rp);
+		restore_flags(flags);
+	       
+		if (!card_present)
+			continue;
+
+		printk(KERN_DEBUG "Now probing slot %X at %p\n", slot, rp);
+		dp = *rp;
+		if(dp == 0)
+			continue;
+
+		/* The last byte of the format block consists of two
+		   nybbles which are "mirror images" of each other.
+		   These show us the valid bytelanes */
+		if ((((dp>>4) ^ dp) & 0x0F) != 0x0F)
+			continue;
+		/* Check that this value is actually *on* one of the
+		   bytelanes it claims are valid! */
+		if ((dp & 0x0F) >= (1<<i))
+			continue;
+
+		/* Looks promising.  Let's put it on the list. */
+		nubus_add_board(slot, dp);
+
+		return;
+	}
+}
+
+#if defined(CONFIG_PROC_FS)
+
+/* /proc/nubus stuff */
+
+static int sprint_nubus_board(struct nubus_board* board, char* ptr, int len)
 {
-	if(len<150)
+	if(len < 100)
 		return -1;
-	sprintf(ptr, "Device: %s %s\n", nubus_slots[slot].slot_cardname,
-		(nubus_slots[slot].slot_flags&NUBUS_DEVICE_ACTIVE)?
-			"[active]":"[unused]");
+	
+	sprintf(ptr, "Slot %X: %s\n",
+		board->slot, board->name);
+	
 	return strlen(ptr);
 }
 
+/* We're going to have to be a bit more sophisticated about this, I
+   think, because it doesn't really seem to work right when you do a
+   full listing of boards and devices */
 int get_nubus_list(char *buf)
 {
 	int nprinted, len, size;
-	int slot;
+	struct nubus_board* board;
 #define MSG "\nwarning: page-size limit reached!\n"
 
 	/* reserve same for truncation warning message: */
 	size  = PAGE_SIZE - (strlen(MSG) + 1);
-	len   = sprintf(buf, "Nubus devices found:\n");
+	len   = sprintf(buf, "Nubus boards found:\n");
 
-	for (slot=0; slot< 16; slot++) 
+	/* Walk the list of NuBus boards */
+	for (board = nubus_boards; board != NULL; board = board->next)
 	{
-		if(!(nubus_slots[slot].slot_flags&NUBUS_DEVICE_PRESENT))
-			continue;
-		nprinted = sprint_nubus_config(slot, buf + len, size - len);
+		nprinted = sprint_nubus_board(board, buf + len, size - len);
 		if (nprinted < 0) {
 			return len + sprintf(buf + len, MSG);
 		}
@@ -594,46 +988,53 @@
 	return len;
 }
 
-static struct proc_dir_entry proc_nubus = {
+static struct proc_dir_entry proc_old_nubus = {
 	PROC_NUBUS, 5, "nubus",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
-#endif
+#endif /* CONFIG_PROC_FS */
 
-void nubus_init(void)
+void __init nubus_scan_bus(void)
 {
-	/* 
-	 *	Register cards
-	 */
-#ifdef CONFIG_DAYNAPORT
-	extern struct nubus_device_specifier nubus_8390;	
+	int slot;
+	/* This might not work on your machine */
+#ifdef I_WANT_TO_PROBE_SLOT_ZERO
+	nubus_probe_slot(0);
 #endif
+	for(slot = 9; slot < 15; slot++)
+	{
+		nubus_probe_slot(slot);
+	}
+}
 
+void __init nubus_init(void)
+{
 	if (!MACH_IS_MAC) 
 		return;
 
-#ifdef LCIII_WEIRDNESS
-	if (macintosh_config->ident == MAC_MODEL_LCIII) {
-	        printk("nubus init: LCIII has no nubus!\n");
-		return;
+	/* Initialize the NuBus interrupts */
+	if (oss_present) {
+		oss_nubus_init();
+	} else {
+		via_nubus_init();
 	}
-#endif
 
-#ifdef CONFIG_DAYNAPORT
-	register_nubus_device(&nubus_8390);
+#ifdef TRY_TO_DODGE_WSOD
+	/* Rogue Ethernet interrupts can kill the machine if we don't
+	   do this.  Obviously this is bogus.  Hopefully the local VIA
+	   gurus can fix the real cause of the problem. */
+	mdelay(1000);
 #endif
+	
+	/* And probe */
+	printk("NuBus: Scanning NuBus slots.\n");
+	nubus_devices = NULL;
+	nubus_boards  = NULL;
+	nubus_scan_bus();
 
-	/*
-	 *	And probe
-	 */
-	 
-	nubus_init_via();
-	printk("Scanning nubus slots.\n");
-	nubus_probe_bus();
 #ifdef CONFIG_PROC_FS
-	proc_register(&proc_root, &proc_nubus);
+	proc_register(&proc_root, &proc_old_nubus);
+	nubus_proc_init();
 #endif
 }
-
-	
\ No newline at end of file
diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/nubus_syms.c linux/drivers/nubus/nubus_syms.c
--- v2.3.16/linux/drivers/nubus/nubus_syms.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/nubus/nubus_syms.c	Sat Sep  4 13:08:32 1999
@@ -0,0 +1,27 @@
+/* Exported symbols for NuBus services
+
+   (c) 1999 David Huggins-Daines <dhd@debian.org> */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/nubus.h>
+
+#ifdef CONFIG_PROC_FS
+EXPORT_SYMBOL(nubus_proc_attach_device);
+EXPORT_SYMBOL(nubus_proc_detach_device);
+#endif
+
+EXPORT_SYMBOL(nubus_find_device);
+EXPORT_SYMBOL(nubus_find_type);
+EXPORT_SYMBOL(nubus_find_slot);
+EXPORT_SYMBOL(nubus_get_root_dir);
+EXPORT_SYMBOL(nubus_get_board_dir);
+EXPORT_SYMBOL(nubus_get_func_dir);
+EXPORT_SYMBOL(nubus_readdir);
+EXPORT_SYMBOL(nubus_find_rsrc);
+EXPORT_SYMBOL(nubus_rewinddir);
+EXPORT_SYMBOL(nubus_get_subdir);
+EXPORT_SYMBOL(nubus_get_rsrc_mem);
+EXPORT_SYMBOL(nubus_get_rsrc_str);
+
diff -u --recursive --new-file v2.3.16/linux/drivers/nubus/proc.c linux/drivers/nubus/proc.c
--- v2.3.16/linux/drivers/nubus/proc.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/nubus/proc.c	Sat Sep  4 13:08:32 1999
@@ -0,0 +1,183 @@
+/* drivers/nubus/proc.c: Proc FS interface for NuBus.
+
+   By David Huggins-Daines <dhd@debian.org>
+
+   Much code and many ideas from drivers/pci/proc.c:
+   Copyright (c) 1997, 1998 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+
+   This is initially based on the Zorro and PCI interfaces.  However,
+   it works somewhat differently.  The intent is to provide a
+   structure in /proc analogous to the structure of the NuBus ROM
+   resources.
+
+   Therefore each NuBus device is in fact a directory, which may in
+   turn contain subdirectories.  The "files" correspond to NuBus
+   resource records.  For those types of records which we know how to
+   convert to formats that are meaningful to userspace (mostly just
+   icons) these files will provide "cooked" data.  Otherwise they will
+   simply provide raw access (read-only of course) to the ROM.  */
+
+#include <linux/config.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/nubus.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+int
+get_nubus_dev_info(char *buf, char **start, off_t pos, int count, int wr)
+{
+	struct nubus_dev *dev = nubus_devices;
+	off_t at = 0;
+	int len, cnt;
+
+	cnt = 0;
+	while (dev && count > cnt) {
+		len = sprintf(buf, "%x\t%04x %04x %04x %04x",
+			      dev->board->slot,
+			      dev->category,
+			      dev->type,
+			      dev->dr_sw,
+			      dev->dr_hw);
+		len += sprintf(buf+len,
+			       "\t%08lx",
+			       dev->board->slot_addr);
+		buf[len++] = '\n';
+		at += len;
+		if (at >= pos) {
+			if (!*start) {
+				*start = buf + (pos - (at - len));
+				cnt = at - pos;
+			} else
+				cnt += len;
+			buf += len;
+		}
+		dev = dev->next;
+	}
+	return (count > cnt) ? cnt : count;
+}
+
+static struct proc_dir_entry proc_nubus_devices = {
+	PROC_BUS_NUBUS_DEVICES, 7, "devices",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations,
+	get_nubus_dev_info
+};
+
+static struct proc_dir_entry *proc_bus_nubus_dir;
+
+static void nubus_proc_subdir(struct nubus_dev* dev,
+			      struct proc_dir_entry* parent,
+			      struct nubus_dir* dir)
+{
+	struct nubus_dirent ent;
+
+	/* Some of these are directories, others aren't */
+	while (nubus_readdir(dir, &ent) != -1) {
+		char name[8];
+		struct proc_dir_entry* e;
+		
+		sprintf(name, "%x", ent.type);
+		e = create_proc_entry(name, S_IFREG | S_IRUGO |
+				      S_IWUSR, parent);
+		if (!e) return;
+	}
+}
+
+/* Can't do this recursively since the root directory is structured
+   somewhat differently from the subdirectories */
+static void nubus_proc_populate(struct nubus_dev* dev,
+				struct proc_dir_entry* parent,
+				struct nubus_dir* root)
+{
+	struct nubus_dirent ent;
+
+	/* We know these are all directories (board resource + one or
+	   more functional resources) */
+	while (nubus_readdir(root, &ent) != -1) {
+		char name[8];
+		struct proc_dir_entry* e;
+		struct nubus_dir dir;
+		
+		sprintf(name, "%x", ent.type);
+		e = create_proc_entry(name, S_IFDIR, parent);
+		if (!e) return;
+
+		/* And descend */
+		if (nubus_get_subdir(&ent, &dir) == -1) {
+			/* This shouldn't happen */
+			printk(KERN_ERR "NuBus root directory node %x:%x has no subdir!\n",
+			       dev->board->slot, ent.type);
+			continue;
+		} else {
+			nubus_proc_subdir(dev, e, &dir);
+		}
+	}
+}
+
+int nubus_proc_attach_device(struct nubus_dev *dev)
+{
+	struct proc_dir_entry *e;
+	struct nubus_dir root;
+	char name[8];
+
+	if (dev == NULL) {
+		printk(KERN_ERR
+		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
+		return -1;
+	}
+		
+	if (dev->board == NULL) {
+		printk(KERN_ERR
+		       "NULL pointer in nubus_proc_attach_device, shoot the programmer!\n");
+		printk("dev = %p, dev->board = %p\n", dev, dev->board);
+		return -1;
+	}
+		
+	/* Create a directory */
+	sprintf(name, "%x", dev->board->slot);
+	e = dev->procdir = create_proc_entry(name, S_IFDIR,
+					     proc_bus_nubus_dir);
+	if (!e)
+		return -ENOMEM;
+
+	/* Now recursively populate it with files */
+	nubus_get_root_dir(dev->board, &root);
+	nubus_proc_populate(dev, e, &root);
+
+	return 0;
+}
+
+/* FIXME: this is certainly broken! */
+int nubus_proc_detach_device(struct nubus_dev *dev)
+{
+	struct proc_dir_entry *e;
+
+	if ((e = dev->procdir)) {
+		if (e->count)
+			return -EBUSY;
+		remove_proc_entry(e->name, proc_bus_nubus_dir);
+		dev->procdir = NULL;
+	}
+	return 0;
+}
+
+void __init proc_bus_nubus_add_devices(void)
+{
+	struct nubus_dev *dev;
+	
+	for(dev = nubus_devices; dev; dev = dev->next)
+		nubus_proc_attach_device(dev);
+}
+
+void __init nubus_proc_init(void)
+{
+	if (!MACH_IS_MAC)
+		return;
+	proc_bus_nubus_dir = create_proc_entry("nubus", S_IFDIR, proc_bus);
+	proc_register(proc_bus_nubus_dir, &proc_nubus_devices);
+	proc_bus_nubus_add_devices();
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/pci/Makefile linux/drivers/pci/Makefile
--- v2.3.16/linux/drivers/pci/Makefile	Thu Aug 26 13:05:38 1999
+++ linux/drivers/pci/Makefile	Wed Sep  1 14:37:25 1999
@@ -25,6 +25,6 @@
 L_OBJS   += proc.o
 endif
 
-L_OBJS   += compat.o quirks.o names.o
+L_OBJS   += compat.o quirks.o names.o syscall.o setup.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.3.16/linux/drivers/pci/pci.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/pci/pci.c	Wed Sep  1 14:37:25 1999
@@ -295,7 +295,7 @@
 	pci_write_config_word(dev, PCI_COMMAND, cmd);
 }
 
-static void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
+void __init pci_read_bridge_bases(struct pci_dev *dev, struct pci_bus *child)
 {
 	u8 io_base_lo, io_limit_lo;
 	u16 mem_base_lo, mem_limit_lo, io_base_hi, io_limit_hi;
@@ -513,7 +513,6 @@
 			child->primary = bus->secondary;
 			child->subordinate = 0xff;
 			sprintf(child->name, "PCI Bus #%02x", child->number);
-			pci_read_bridge_bases(dev, child);
 			/*
 			 * Clear all status bits and turn off memory,
 			 * I/O and master enables.
diff -u --recursive --new-file v2.3.16/linux/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- v2.3.16/linux/drivers/pci/quirks.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/pci/quirks.c	Wed Sep  1 14:37:25 1999
@@ -67,13 +67,8 @@
 	struct resource *r = &dev->resource[0];
 
 	if ((r->start & 0x3ffffff) || r->end != r->start + 0x3ffffff) {
-		printk("PCI: Re-allocating buggy S3 card at %s: ", dev->name);
 		r->start = 0;
 		r->end = 0x3ffffff;
-		if (pcibios_assign_resource(dev, 0))
-			printk("FAILED\n");
-		else
-			printk("moved to %08lx\n", r->start);
 	}
 }
 
@@ -90,8 +85,8 @@
 	 * quantity.
 	 */
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_0,	quirk_isa_dma_hangs },
-	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M },
-	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_868,		quirk_s3_64M },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_S3,	PCI_DEVICE_ID_S3_968,		quirk_s3_64M },
 	{ 0 }
 };
 
diff -u --recursive --new-file v2.3.16/linux/drivers/pci/setup.c linux/drivers/pci/setup.c
--- v2.3.16/linux/drivers/pci/setup.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/setup.c	Wed Sep  1 14:37:25 1999
@@ -0,0 +1,324 @@
+/*
+ *	drivers/pci/setup.c
+ *
+ * Extruded from code written by
+ *      Dave Rusling (david.rusling@reo.mts.dec.com)
+ *      David Mosberger (davidm@cs.arizona.edu)
+ *	David Miller (davem@redhat.com)
+ *
+ * Support routines for initializing a PCI subsystem.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+
+#include <asm/cache.h>
+#include <asm/pci.h>
+
+
+#define DEBUG_CONFIG 0
+#if DEBUG_CONFIG
+# define DBGC(args)     printk args
+#else
+# define DBGC(args)
+#endif
+
+
+int __init
+pci_claim_resource(struct pci_dev *dev, int resource)
+{
+        struct resource *res = &dev->resource[resource];
+	struct resource *root = pci_find_parent_resource(dev, res);
+	int err;
+
+	err = -EINVAL;
+	if (root != NULL) {
+		/* If `dev' is on a secondary pci bus, `root' may not be
+		   at the origin.  In that case, adjust the resource into
+		   range.  */
+		res->start += root->start;
+		res->end += root->start;
+
+		err = request_resource(root, res);
+	}
+	if (err) {
+		printk(KERN_ERR "PCI: Address space collision on region %d "
+		       "of device %s\n", resource, dev->name);
+	}
+
+	return err;
+}
+
+static void
+pdev_assign_unassigned_resources(struct pci_dev *dev, u32 min_io, u32 min_mem)
+{
+	u32 reg;
+	u16 cmd;
+	int i;
+
+	DBGC(("PCI assign unassigned: (%s)\n", dev->name));
+
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		struct resource *root, *res;
+		unsigned long size, min;
+
+		res = &dev->resource[i];
+
+		if (res->flags & IORESOURCE_IO)
+			cmd |= PCI_COMMAND_IO;
+		else if (res->flags & IORESOURCE_MEM)
+			cmd |= PCI_COMMAND_MEMORY;
+
+		/* If it is already assigned or the resource does
+		   not exist, there is nothing to do.  */
+		if (res->parent != NULL || res->flags == 0)
+			continue;
+
+		/* Determine the root we allocate from.  */
+		root = pci_find_parent_resource(dev, res);
+		if (root == NULL)
+			continue;
+
+		min = (res->flags & IORESOURCE_IO ? min_io : min_mem);
+		min += root->start;
+		size = res->end - res->start + 1;
+
+		DBGC(("  for root[%lx:%lx] min[%lx] size[%lx]\n",
+		      root->start, root->end, min, size));
+
+		if (allocate_resource(root, res, size, min, -1, size) < 0) {
+			printk(KERN_ERR
+			       "PCI: Failed to allocate resource %d for %s\n",
+			       i, dev->name);
+			continue;
+		}
+
+		DBGC(("  got res[%lx:%lx] for resource %d\n",
+		      res->start, res->end, i));
+
+		/* Update PCI config space.  */
+		pcibios_update_resource(dev, root, res, i);
+	}
+
+	/* Special case, disable the ROM.  Several devices act funny
+	   (ie. do not respond to memory space writes) when it is left
+	   enabled.  A good example are QlogicISP adapters.  */
+
+	pci_read_config_dword(dev, PCI_ROM_ADDRESS, &reg);
+	reg &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_dword(dev, PCI_ROM_ADDRESS, reg);
+
+	/* All of these (may) have I/O scattered all around and may not
+	   use I/O base address registers at all.  So we just have to
+	   always enable IO to these devices.  */
+	if ((dev->class >> 8) == PCI_CLASS_NOT_DEFINED
+	    || (dev->class >> 8) == PCI_CLASS_NOT_DEFINED_VGA
+	    || (dev->class >> 8) == PCI_CLASS_STORAGE_IDE
+	    || (dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
+		cmd |= PCI_COMMAND_IO;
+	}
+
+	/* ??? Always turn on bus mastering.  If the device doesn't support
+	   it, the bit will go into the bucket. */
+	cmd |= PCI_COMMAND_MASTER;
+
+	/* Enable the appropriate bits in the PCI command register.  */
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+	DBGC(("  cmd reg 0x%x\n", cmd));
+
+	/* If this is a PCI bridge, set the cache line correctly.  */
+	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+				      (L1_CACHE_BYTES / sizeof(u32)));
+	}
+}
+
+void __init
+pci_assign_unassigned_resources(u32 min_io, u32 min_mem)
+{
+	struct pci_dev *dev;
+	for (dev = pci_devices; dev; dev = dev->next)
+		pdev_assign_unassigned_resources(dev, min_io, min_mem);
+}
+
+struct pbus_set_ranges_data
+{
+	int found_vga;
+	unsigned int io_start, io_end;
+	unsigned int mem_start, mem_end;
+};
+
+#define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+#define ROUND_DOWN(x, a)	((x) & ~((a) - 1))
+
+static void __init
+pbus_set_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *outer)
+{
+	struct pbus_set_ranges_data inner;
+	struct pci_bus *child;
+	struct pci_dev *dev;
+
+	inner.found_vga = 0;
+	inner.mem_start = inner.io_start = ~0;
+	inner.mem_end = inner.io_end = 0;
+
+	/* Collect information about how our direct children are layed out. */
+	for (dev = bus->devices; dev; dev = dev->sibling) {
+		int i;
+		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+			struct resource *res = &dev->resource[i];
+			if (res->flags & IORESOURCE_IO) {
+				if (res->start < inner.io_start)
+					inner.io_start = res->start;
+				if (res->end > inner.io_end)
+					inner.io_end = res->end;
+			} else if (res->flags & IORESOURCE_MEM) {
+				if (res->start < inner.mem_start)
+					inner.mem_start = res->start;
+				if (res->end > inner.mem_end)
+					inner.mem_end = res->end;
+			}
+		}
+                if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+                        inner.found_vga = 1;
+	}
+
+	/* And for all of the sub-busses.  */
+	for (child = bus->children; child; child = child->next)
+		pbus_set_ranges(child, &inner);
+
+	/* Align the values.  */
+	inner.io_start = ROUND_DOWN(inner.io_start, 4*1024);
+	inner.io_end = ROUND_UP(inner.io_end, 4*1024);
+
+	inner.mem_start = ROUND_DOWN(inner.mem_start, 1*1024*1024);
+	inner.mem_end = ROUND_UP(inner.mem_end, 1*1024*1024);
+
+	/* Configure the bridge, if possible.  */
+	if (bus->self) {
+		struct pci_dev *bridge = bus->self;
+		u32 l;
+
+                /* Set up the top and bottom of the PCI I/O segment
+                   for this bus.  */
+                pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+                l &= 0xffff0000;
+                l |= (inner.io_start >> 8) & 0x00f0;
+		l |= (inner.io_end - 1) & 0xf000;
+                pci_write_config_dword(bridge, PCI_IO_BASE, l);
+
+                /*
+                 * Clear out the upper 16 bits of IO base/limit.
+                 * Clear out the upper 32 bits of PREF base/limit.
+                 */
+                pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0);
+                pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+                pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
+
+                /* Set up the top and bottom of the PCI Memory segment
+                   for this bus.  */
+                l = (inner.mem_start & 0xfff00000) >> 16;
+		l |= (inner.mem_end - 1) & 0xfff00000;
+                pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+                /*
+                 * Turn off downstream PF memory address range, unless
+                 * there is a VGA behind this bridge, in which case, we
+                 * enable the PREFETCH range to include BIOS ROM at C0000.
+                 *
+                 * NOTE: this is a bit of a hack, done with PREFETCH for
+                 * simplicity, rather than having to add it into the above
+                 * non-PREFETCH range, which could then be bigger than we want.
+                 * We might assume that we could relocate the BIOS ROM, but
+                 * that would depend on having it found by those who need it
+                 * (the DEC BIOS emulator would find it, but I do not know
+                 * about the Xservers). So, we do it this way for now... ;-)
+                 */
+                l = (inner.found_vga) ? 0 : 0x0000ffff;
+                pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+                /*
+                 * Tell bridge that there is an ISA bus in the system,
+                 * and (possibly) a VGA as well.
+                 */
+                l = (inner.found_vga) ? 0x0c : 0x04;
+                pci_write_config_byte(bridge, PCI_BRIDGE_CONTROL, l);
+
+                /*
+                 * Clear status bits,
+                 * turn on I/O    enable (for downstream I/O),
+                 * turn on memory enable (for downstream memory),
+                 * turn on master enable (for upstream memory and I/O).
+                 */
+                pci_write_config_dword(bridge, PCI_COMMAND, 0xffff0007);
+	}
+
+	if (outer) {
+		outer->found_vga |= inner.found_vga;
+		if (inner.io_start < outer->io_start)
+			outer->io_start = inner.io_start;
+		if (inner.io_end > outer->io_end)
+			outer->io_end = inner.io_end;
+		if (inner.mem_start < outer->mem_start)
+			outer->mem_start = inner.mem_start;
+		if (inner.mem_end > outer->mem_end)
+			outer->mem_end = inner.mem_end;
+	}
+}
+
+void __init
+pci_set_bus_ranges(void)
+{
+	struct pci_bus *bus;
+	for (bus = pci_root; bus; bus = bus->next)
+		pbus_set_ranges(bus, NULL);
+}
+
+static void
+pdev_fixup_irq(struct pci_dev *dev,
+	       u8 (*swizzle)(struct pci_dev *, u8 *),
+	       int (*map_irq)(struct pci_dev *, u8, u8))
+{
+	u8 pin, slot;
+	int irq;
+
+	/* If this device is not on the primary bus, we need to figure out
+	   which interrupt pin it will come in on.   We know which slot it
+	   will come in on 'cos that slot is where the bridge is.   Each
+	   time the interrupt line passes through a PCI-PCI bridge we must
+	   apply the swizzle function.  */
+
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	/* Cope with 0 and illegal. */
+	if (pin == 0 || pin > 4)
+		pin = 1;
+
+	/* Follow the chain of bridges, swizzling as we go.  */
+	slot = (*swizzle)(dev, &pin);
+
+	irq = (*map_irq)(dev, slot, pin);
+	if (irq == -1)
+		irq = 0;
+	dev->irq = irq;
+
+	DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq));
+
+	/* Always tell the device, so the driver knows what is
+	   the real IRQ to use; the device does not use it. */
+	pcibios_update_irq(dev, irq);
+}
+
+void __init
+pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
+	       int (*map_irq)(struct pci_dev *, u8, u8))
+{
+	struct pci_dev *dev;
+	for (dev = pci_devices; dev; dev = dev->next)
+		pdev_fixup_irq(dev, swizzle, map_irq);
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/pci/syscall.c linux/drivers/pci/syscall.c
--- v2.3.16/linux/drivers/pci/syscall.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pci/syscall.c	Wed Sep  1 16:41:09 1999
@@ -0,0 +1,145 @@
+/*
+ *	pci_syscall.c
+ *
+ * For architectures where we want to allow direct access
+ * to the PCI config stuff - it would probably be preferable
+ * on PCs too, but there people just do it by hand with the
+ * magic northbridge registers..
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+
+
+asmlinkage long
+sys_pciconfig_read(unsigned long bus, unsigned long dfn,
+		   unsigned long off, unsigned long len, void *buf)
+{
+	struct pci_dev *dev;
+	u8 byte;
+	u16 word;
+	u32 dword;
+	long err, cfg_ret;
+
+	err = -EPERM;
+	if (!capable(CAP_SYS_ADMIN))
+		goto error;
+
+	err = -ENODEV;
+	dev = pci_find_slot(bus, dfn);
+	if (!dev)
+		goto error;
+
+	lock_kernel();
+	switch (len) {
+	case 1:
+		cfg_ret = pci_read_config_byte(dev, off, &byte);
+		break;
+	case 2:
+		cfg_ret = pci_read_config_word(dev, off, &word);
+		break;
+	case 4:
+		cfg_ret = pci_read_config_dword(dev, off, &dword);
+		break;
+	default:
+		err = -EINVAL;
+		unlock_kernel();
+		goto error;
+	};
+	unlock_kernel();
+
+	err = -EIO;
+	if (cfg_ret != PCIBIOS_SUCCESSFUL)
+		goto error;
+
+	switch (len) {
+	case 1:
+		err = put_user(byte, (unsigned char *)buf);
+		break;
+	case 2:
+		err = put_user(word, (unsigned short *)buf);
+		break;
+	case 4:
+		err = put_user(dword, (unsigned int *)buf);
+		break;
+	};
+	return err;
+
+error:
+	/* ??? XFree86 doesn't even check the return value.  They
+	   just look for 0xffffffff in the output, since that's what
+	   they get instead of a machine check on x86.  */
+	switch (len) {
+	case 1:
+		put_user(-1, (unsigned char *)buf);
+		break;
+	case 2:
+		put_user(-1, (unsigned short *)buf);
+		break;
+	case 4:
+		put_user(-1, (unsigned int *)buf);
+		break;
+	};
+	return err;
+}
+
+asmlinkage long
+sys_pciconfig_write(unsigned long bus, unsigned long dfn,
+		    unsigned long off, unsigned long len, void *buf)
+{
+	struct pci_dev *dev;
+	u8 byte;
+	u16 word;
+	u32 dword;
+	int err = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	if (!pcibios_present())
+		return -ENOSYS;
+
+	dev = pci_find_slot(bus, dfn);
+	if (!dev)
+		return -ENODEV;
+
+	lock_kernel();
+	switch(len) {
+	case 1:
+		err = get_user(byte, (u8 *)buf);
+		if (err)
+			break;
+		err = pci_write_config_byte(dev, off, byte);
+		if (err != PCIBIOS_SUCCESSFUL)
+			err = -EIO;
+		break;
+
+	case 2:
+		err = get_user(word, (u16 *)buf);
+		if (err)
+			break;
+		err = pci_write_config_byte(dev, off, word);
+		if (err != PCIBIOS_SUCCESSFUL)
+			err = -EIO;
+		break;
+
+	case 4:
+		err = get_user(dword, (u32 *)buf);
+		if (err)
+			break;
+		pci_write_config_byte(dev, off, dword);
+		if (err != PCIBIOS_SUCCESSFUL)
+			err = -EIO;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	};
+	unlock_kernel();
+
+	return err;
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/Config.in linux/drivers/pcmcia/Config.in
--- v2.3.16/linux/drivers/pcmcia/Config.in	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/Config.in	Fri Sep  3 12:36:41 1999
@@ -0,0 +1,12 @@
+#
+# PCMCIA bus subsystem configuration
+#
+mainmenu_option next_comment
+comment 'PCMCIA/Cardbus support'
+
+tristate 'PCMCIA/Cardbus support' CONFIG_PCMCIA
+if [ "$CONFIG_PCMCIA" != "n" ]; then
+  bool '  CardBus support' CONFIG_CARDBUS
+fi
+
+endmenu
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/Makefile linux/drivers/pcmcia/Makefile
--- v2.3.16/linux/drivers/pcmcia/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/Makefile	Fri Sep  3 14:21:38 1999
@@ -0,0 +1,28 @@
+#
+# Makefile for the kernel pcmcia subsystem (c/o David Hinds)
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+O_TARGET := pcmcia.o
+
+O_OBJS   := i82365.o tcic.o cistpl.o rsrc_mgr.o bulkmem.o
+OX_OBJS  := ds.o cs.o
+
+ifeq ($(CONFIG_CARDBUS),y)
+  O_OBJS += cardbus.o
+else
+  ifeq ($(CONFIG_CARDBUS),m)
+    MX_OBJS += cardbus.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/bulkmem.c linux/drivers/pcmcia/bulkmem.c
--- v2.3.16/linux/drivers/pcmcia/bulkmem.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/bulkmem.c	Fri Sep  3 13:41:38 1999
@@ -0,0 +1,624 @@
+/*======================================================================
+
+    PCMCIA Bulk Memory Services
+
+    bulkmem.c 1.29 1999/08/28 04:01:45
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+/*======================================================================
+
+    This function handles submitting an MTD request, and retrying
+    requests when an MTD is busy.
+
+    An MTD request should never block.
+    
+======================================================================*/
+
+static int do_mtd_request(memory_handle_t handle, mtd_request_t *req,
+			  caddr_t buf)
+{
+    int ret, tries;
+    client_t *mtd;
+    socket_info_t *s;
+    
+    mtd = handle->mtd;
+    if (mtd == NULL)
+	return CS_GENERAL_FAILURE;
+    s = SOCKET(mtd);
+    for (tries = 0; tries < 100; tries++) {
+	mtd->event_callback_args.mtdrequest = req;
+	mtd->event_callback_args.buffer = buf;
+	ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+	if (ret != CS_BUSY)
+	    break;
+	switch (req->Status) {
+	case MTD_WAITREQ:
+	    /* Not that we should ever need this... */
+	    interruptible_sleep_on_timeout(&mtd->mtd_req, HZ);
+	    break;
+	case MTD_WAITTIMER:
+	case MTD_WAITRDY:
+	    interruptible_sleep_on_timeout(&mtd->mtd_req, req->Timeout*HZ/1000);
+	    req->Function |= MTD_REQ_TIMEOUT;
+	    break;
+	case MTD_WAITPOWER:
+	    interruptible_sleep_on(&mtd->mtd_req);
+	    break;
+	}
+	if (signal_pending(current))
+	    printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n");
+    }
+    if (tries == 20) {
+	printk(KERN_NOTICE "cs: MTD request timed out!\n");
+	ret = CS_GENERAL_FAILURE;
+    }
+    wake_up_interruptible(&mtd->mtd_req);
+    retry_erase_list(&mtd->erase_busy, 0);
+    return ret;
+} /* do_mtd_request */
+
+/*======================================================================
+
+    This stuff is all for handling asynchronous erase requests.  It
+    is complicated because all the retry stuff has to be dealt with
+    in timer interrupts or in the card status event handler.
+
+======================================================================*/
+
+static void insert_queue(erase_busy_t *head, erase_busy_t *entry)
+{
+    DEBUG(2, ("cs: adding 0x%p to queue 0x%p\n", entry, head));
+    entry->next = head;
+    entry->prev = head->prev;
+    head->prev->next = entry;
+    head->prev = entry;
+}
+
+static void remove_queue(erase_busy_t *entry)
+{
+    DEBUG(2, ("cs: unqueueing 0x%p\n", entry));
+    entry->next->prev = entry->prev;
+    entry->prev->next = entry->next;
+}
+
+static void retry_erase(erase_busy_t *busy, u_int cause)
+{
+    eraseq_entry_t *erase = busy->erase;
+    mtd_request_t req;
+    client_t *mtd;
+    socket_info_t *s;
+    int ret;
+
+    DEBUG(2, ("cs: trying erase request 0x%p...\n", busy));
+    if (busy->next)
+	remove_queue(busy);
+    req.Function = MTD_REQ_ERASE | cause;
+    req.TransferLength = erase->Size;
+    req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset;
+    req.MediaID = erase->Handle->MediaID;
+    mtd = erase->Handle->mtd;
+    s = SOCKET(mtd);
+    mtd->event_callback_args.mtdrequest = &req;
+    ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+    if (ret == CS_BUSY) {
+	DEBUG(2, ("  Status = %d, requeueing.\n", req.Status));
+	switch (req.Status) {
+	case MTD_WAITREQ:
+	case MTD_WAITPOWER:
+	    insert_queue(&mtd->erase_busy, busy);
+	    break;
+	case MTD_WAITTIMER:
+	case MTD_WAITRDY:
+	    if (req.Status == MTD_WAITRDY)
+		insert_queue(&s->erase_busy, busy);
+	    busy->timeout.expires = jiffies + req.Timeout*HZ/1000;
+	    add_timer(&busy->timeout);
+	    break;
+	}
+    } else {
+	/* update erase queue status */
+	DEBUG(2, ("  Ret = %d\n", ret));
+	switch (ret) {
+	case CS_SUCCESS:
+	    erase->State = ERASE_PASSED; break;
+	case CS_WRITE_PROTECTED:
+	    erase->State = ERASE_MEDIA_WRPROT; break;
+	case CS_BAD_OFFSET:
+	    erase->State = ERASE_BAD_OFFSET; break;
+	case CS_BAD_SIZE:
+	    erase->State = ERASE_BAD_SIZE; break;
+	case CS_NO_CARD:
+	    erase->State = ERASE_BAD_SOCKET; break;
+	default:
+	    erase->State = ERASE_FAILED; break;
+	}
+	busy->client->event_callback_args.info = erase;
+	EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW);
+	kfree_s(busy, sizeof(*busy));
+	/* Resubmit anything waiting for a request to finish */
+	wake_up_interruptible(&mtd->mtd_req);
+	retry_erase_list(&mtd->erase_busy, 0);
+    }
+} /* retry_erase */
+
+void retry_erase_list(erase_busy_t *list, u_int cause)
+{
+    erase_busy_t tmp = *list;
+
+    DEBUG(2, ("cs: rescanning erase queue list 0x%p\n", list));
+    if (list->next == list)
+	return;
+    /* First, truncate the original list */
+    list->prev->next = &tmp;
+    list->next->prev = &tmp;
+    list->prev = list->next = list;
+    tmp.prev->next = &tmp;
+    tmp.next->prev = &tmp;
+
+    /* Now, retry each request, in order. */
+    while (tmp.next != &tmp)
+	retry_erase(tmp.next, cause);
+} /* retry_erase_list */
+
+static void handle_erase_timeout(u_long arg)
+{
+    DEBUG(0, ("cs: erase timeout for entry 0x%lx\n", arg));
+    retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
+}
+
+static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+{
+    erase_busy_t *busy;
+    region_info_t *info;
+    
+    if (CHECK_REGION(erase->Handle))
+	erase->State = ERASE_BAD_SOCKET;
+    else {
+	info = &erase->Handle->info;
+	if ((erase->Offset >= info->RegionSize) ||
+	    (erase->Offset & (info->BlockSize-1)))
+	    erase->State = ERASE_BAD_OFFSET;
+	else if ((erase->Offset+erase->Size > info->RegionSize) ||
+		 (erase->Size & (info->BlockSize-1)))
+	    erase->State = ERASE_BAD_SIZE;
+	else {
+	    erase->State = 1;
+	    busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
+	    busy->erase = erase;
+	    busy->client = handle;
+	    busy->timeout.prev = busy->timeout.next = NULL;
+	    busy->timeout.data = (u_long)busy;
+	    busy->timeout.function = &handle_erase_timeout;
+	    busy->prev = busy->next = NULL;
+	    retry_erase(busy, 0);
+	}
+    }
+} /* setup_erase_request */
+
+/*======================================================================
+
+    MTD helper functions
+
+======================================================================*/
+
+static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req)
+{
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+	return CS_BAD_HANDLE;
+    win->ctl.flags = MAP_16BIT | MAP_ACTIVE;
+    if (req->Attributes & WIN_USE_WAIT)
+	win->ctl.flags |= MAP_USE_WAIT;
+    if (req->Attributes & WIN_MEMORY_TYPE)
+	win->ctl.flags |= MAP_ATTRIB;
+    win->ctl.speed = req->AccessSpeed;
+    win->ctl.card_start = req->CardOffset;
+    win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
+    return CS_SUCCESS;
+}
+
+static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    if (req->Vpp1 != req->Vpp2)
+	return CS_BAD_VPP;
+    s = SOCKET(handle);
+    s->socket.Vpp = req->Vpp1;
+    if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+	return CS_BAD_VPP;
+    return CS_SUCCESS;
+}
+
+static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (req->Mask & CS_EVENT_READY_CHANGE)
+	s->socket.csc_mask |= SS_READY;
+    else
+	s->socket.csc_mask &= ~SS_READY;
+    if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+	return CS_GENERAL_FAILURE;
+    return CS_SUCCESS;
+}
+
+int MTDHelperEntry(int func, void *a1, void *a2)
+{
+    switch (func) {
+    case MTDRequestWindow:
+	return CardServices(RequestWindow, a1, a2, NULL);
+    case MTDReleaseWindow:
+	return CardServices(ReleaseWindow, a1, NULL, NULL);
+    case MTDModifyWindow:
+	return mtd_modify_window(a1, a2); break;
+    case MTDSetVpp:
+	return mtd_set_vpp(a1, a2); break;
+    case MTDRDYMask:
+	return mtd_rdy_mask(a1, a2); break;
+    default:
+	return CS_UNSUPPORTED_FUNCTION; break;
+    }
+} /* MTDHelperEntry */
+
+/*======================================================================
+
+    This stuff is used by Card Services to initialize the table of
+    region info used for subsequent calls to GetFirstRegion and
+    GetNextRegion.
+    
+======================================================================*/
+
+static void setup_regions(client_handle_t handle, int attr,
+			  memory_handle_t *list)
+{
+    int i, code, has_jedec, has_geo;
+    u_int offset;
+    cistpl_device_t device;
+    cistpl_jedec_t jedec;
+    cistpl_device_geo_t geo;
+    memory_handle_t r;
+
+    DEBUG(1, ("cs: setup_regions(0x%p, %d, 0x%p)\n",
+	      handle, attr, list));
+
+    code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
+    if (read_tuple(handle, code, &device) != CS_SUCCESS)
+	return;
+    code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
+    has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
+    if (has_jedec && (device.ndev != jedec.nid)) {
+#ifdef PCMCIA_DEBUG
+	printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n");
+#endif
+	has_jedec = 0;
+    }
+    code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
+    has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS);
+    if (has_geo && (device.ndev != geo.ngeo)) {
+#ifdef PCMCIA_DEBUG
+	printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n");
+#endif
+	has_geo = 0;
+    }
+    
+    offset = 0;
+    for (i = 0; i < device.ndev; i++) {
+	if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
+	    (device.dev[i].size != 0)) {
+	    r = kmalloc(sizeof(*r), GFP_KERNEL);
+	    r->region_magic = REGION_MAGIC;
+	    r->state = 0;
+	    r->dev_info[0] = '\0';
+	    r->mtd = NULL;
+	    r->info.Attributes = (attr) ? REGION_TYPE_AM : 0;
+	    r->info.CardOffset = offset;
+	    r->info.RegionSize = device.dev[i].size;
+	    r->info.AccessSpeed = device.dev[i].speed;
+	    if (has_jedec) {
+		r->info.JedecMfr = jedec.id[i].mfr;
+		r->info.JedecInfo = jedec.id[i].info;
+	    } else
+		r->info.JedecMfr = r->info.JedecInfo = 0;
+	    if (has_geo) {
+		r->info.BlockSize = geo.geo[i].buswidth *
+		    geo.geo[i].erase_block * geo.geo[i].interleave;
+		r->info.PartMultiple =
+		    r->info.BlockSize * geo.geo[i].partition;
+	    } else
+		r->info.BlockSize = r->info.PartMultiple = 1;
+	    r->info.next = *list; *list = r;
+	}
+	offset += device.dev[i].size;
+    }
+} /* setup_regions */
+
+/*======================================================================
+
+    This is tricky.  When get_first_region() is called by Driver
+    Services, we initialize the region info table in the socket
+    structure.  When it is called by an MTD, we can just scan the
+    table for matching entries.
+    
+======================================================================*/
+
+static int match_region(client_handle_t handle, memory_handle_t list,
+			region_info_t *match)
+{
+    while (list != NULL) {
+	if (!(handle->Attributes & INFO_MTD_CLIENT) ||
+	    (strcmp(handle->dev_info, list->dev_info) == 0)) {
+	    *match = list->info;
+	    return CS_SUCCESS;
+	}
+	list = list->info.next;
+    }
+    return CS_NO_MORE_ITEMS;
+} /* match_region */
+
+int get_first_region(client_handle_t handle, region_info_t *rgn)
+{
+    socket_info_t *s = SOCKET(handle);
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    
+    if ((handle->Attributes & INFO_MASTER_CLIENT) &&
+	(!(s->state & SOCKET_REGION_INFO))) {
+	setup_regions(handle, 0, &s->c_region);
+	setup_regions(handle, 1, &s->a_region);
+	s->state |= SOCKET_REGION_INFO;
+    }
+
+    if (rgn->Attributes & REGION_TYPE_AM)
+	return match_region(handle, s->a_region, rgn);
+    else
+	return match_region(handle, s->c_region, rgn);
+} /* get_first_region */
+
+int get_next_region(client_handle_t handle, region_info_t *rgn)
+{
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    return match_region(handle, rgn->next, rgn);
+} /* get_next_region */
+
+/*======================================================================
+
+    Connect an MTD with a memory region.
+    
+======================================================================*/
+
+int register_mtd(client_handle_t handle, mtd_reg_t *reg)
+{
+    memory_handle_t list;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (reg->Attributes & REGION_TYPE_AM)
+	list = s->a_region;
+    else
+	list = s->c_region;
+    DEBUG(1, ("cs: register_mtd(0x%p, '%s', 0x%x)\n",
+	      handle, handle->dev_info, reg->Offset));
+    while (list) {
+	if (list->info.CardOffset == reg->Offset) break;
+	list = list->info.next;
+    }
+    if (list && (list->mtd == NULL) &&
+	(strcmp(handle->dev_info, list->dev_info) == 0)) {
+	list->info.Attributes = reg->Attributes;
+	list->MediaID = reg->MediaID;
+	list->mtd = handle;
+	handle->mtd_count++;
+	return CS_SUCCESS;
+    } else
+	return CS_BAD_OFFSET;
+} /* register_mtd */
+
+/*======================================================================
+
+    
+    
+======================================================================*/
+
+int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header)
+{
+    eraseq_t *queue;
+
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+	return CS_BAD_HANDLE;
+    queue = kmalloc(sizeof(*queue), GFP_KERNEL);
+    queue->eraseq_magic = ERASEQ_MAGIC;
+    queue->handle = *handle;
+    queue->count = header->QueueEntryCnt;
+    queue->entry = header->QueueEntryArray;
+    *handle = (client_handle_t)queue;
+    return CS_SUCCESS;
+} /* register_erase_queue */
+
+int deregister_erase_queue(eraseq_handle_t eraseq)
+{
+    int i;
+    if (CHECK_ERASEQ(eraseq))
+	return CS_BAD_HANDLE;
+    for (i = 0; i < eraseq->count; i++)
+	if (ERASE_IN_PROGRESS(eraseq->entry[i].State)) break;
+    if (i < eraseq->count)
+	return CS_BUSY;
+    eraseq->eraseq_magic = 0;
+    kfree_s(eraseq, sizeof(*eraseq));
+    return CS_SUCCESS;
+} /* deregister_erase_queue */
+
+int check_erase_queue(eraseq_handle_t eraseq)
+{
+    int i;
+    if (CHECK_ERASEQ(eraseq))
+	return CS_BAD_HANDLE;
+    for (i = 0; i < eraseq->count; i++)
+	if (eraseq->entry[i].State == ERASE_QUEUED)
+	    setup_erase_request(eraseq->handle, &eraseq->entry[i]);
+    return CS_SUCCESS;
+} /* check_erase_queue */
+
+/*======================================================================
+
+    Look up the memory region matching the request, and return a
+    memory handle.
+    
+======================================================================*/
+
+int open_memory(client_handle_t *handle, open_mem_t *open)
+{
+    socket_info_t *s;
+    memory_handle_t region;
+    
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(*handle);
+    if (open->Attributes & MEMORY_TYPE_AM)
+	region = s->a_region;
+    else
+	region = s->c_region;
+    while (region) {
+	if (region->info.CardOffset == open->Offset) break;
+	region = region->info.next;
+    }
+    if (region && region->mtd) {
+	*handle = (client_handle_t)region;
+	DEBUG(1, ("cs: open_memory(0x%p, 0x%x) = 0x%p\n",
+		  handle, open->Offset, region));
+	return CS_SUCCESS;
+    } else
+	return CS_BAD_OFFSET;
+} /* open_memory */
+
+/*======================================================================
+
+    Close a memory handle from an earlier call to OpenMemory.
+    
+    For the moment, I don't think this needs to do anything.
+    
+======================================================================*/
+
+int close_memory(memory_handle_t handle)
+{
+    DEBUG(1, ("cs: close_memory(0x%p)\n", handle));
+    if (CHECK_REGION(handle))
+	return CS_BAD_HANDLE;
+    return CS_SUCCESS;
+} /* close_memory */
+
+/*======================================================================
+
+    Read from a memory device, using a handle previously returned
+    by a call to OpenMemory.
+    
+======================================================================*/
+
+int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
+{
+    mtd_request_t mtd;
+    if (CHECK_REGION(handle))
+	return CS_BAD_HANDLE;
+    if (req->Offset >= handle->info.RegionSize)
+	return CS_BAD_OFFSET;
+    if (req->Offset+req->Count > handle->info.RegionSize)
+	return CS_BAD_SIZE;
+    
+    mtd.SrcCardOffset = req->Offset + handle->info.CardOffset;
+    mtd.TransferLength = req->Count;
+    mtd.MediaID = handle->MediaID;
+    mtd.Function = MTD_REQ_READ;
+    if (req->Attributes & MEM_OP_BUFFER_KERNEL)
+	mtd.Function |= MTD_REQ_KERNEL;
+    return do_mtd_request(handle, &mtd, buf);
+} /* read_memory */
+
+/*======================================================================
+
+    Write to a memory device, using a handle previously returned by
+    a call to OpenMemory.
+    
+======================================================================*/
+
+int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
+{
+    mtd_request_t mtd;
+    if (CHECK_REGION(handle))
+	return CS_BAD_HANDLE;
+    if (req->Offset >= handle->info.RegionSize)
+	return CS_BAD_OFFSET;
+    if (req->Offset+req->Count > handle->info.RegionSize)
+	return CS_BAD_SIZE;
+    
+    mtd.DestCardOffset = req->Offset + handle->info.CardOffset;
+    mtd.TransferLength = req->Count;
+    mtd.MediaID = handle->MediaID;
+    mtd.Function = MTD_REQ_WRITE;
+    if (req->Attributes & MEM_OP_BUFFER_KERNEL)
+	mtd.Function |= MTD_REQ_KERNEL;
+    return do_mtd_request(handle, &mtd, buf);
+} /* write_memory */
+
+/*======================================================================
+
+    
+======================================================================*/
+
+int copy_memory(memory_handle_t handle, copy_op_t *req)
+{
+    if (CHECK_REGION(handle))
+	return CS_BAD_HANDLE;
+    return CS_UNSUPPORTED_FUNCTION;
+} /* close_memory */
+
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cardbus.c linux/drivers/pcmcia/cardbus.c
--- v2.3.16/linux/drivers/pcmcia/cardbus.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/cardbus.c	Tue Sep  7 11:13:24 1999
@@ -0,0 +1,638 @@
+/*======================================================================
+  
+    Cardbus device configuration
+    
+    cardbus.c 1.57 1999/09/07 15:19:32
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+    These routines handle allocating resources for Cardbus cards, as
+    well as setting up and shutting down Cardbus sockets.  They are
+    called from cs.c in response to Request/ReleaseConfiguration and
+    Request/ReleaseIO calls.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#ifndef PCMCIA_DEBUG
+#define PCMCIA_DEBUG 1
+#endif
+static int pc_debug = PCMCIA_DEBUG;
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+/*====================================================================*/
+
+#define FIND_FIRST_BIT(n)	((n) - ((n) & ((n)-1)))
+
+#define pci_readb		pcibios_read_config_byte
+#define pci_writeb		pcibios_write_config_byte
+#define pci_readw		pcibios_read_config_word
+#define pci_writew		pcibios_write_config_word
+#define pci_readl		pcibios_read_config_dword
+#define pci_writel		pcibios_write_config_dword
+
+#define CB_BAR(n)		(PCI_BASE_ADDRESS_0+(4*(n)))
+#define CB_ROM_BASE		0x0030
+
+/* Offsets in the Expansion ROM Image Header */
+#define ROM_SIGNATURE		0x0000	/* 2 bytes */
+#define ROM_DATA_PTR		0x0018	/* 2 bytes */
+
+/* Offsets in the CardBus PC Card Data Structure */
+#define PCDATA_SIGNATURE	0x0000	/* 4 bytes */
+#define PCDATA_VPD_PTR		0x0008	/* 2 bytes */
+#define PCDATA_LENGTH		0x000a	/* 2 bytes */
+#define PCDATA_REVISION		0x000c
+#define PCDATA_IMAGE_SZ		0x0010	/* 2 bytes */
+#define PCDATA_ROM_LEVEL	0x0012	/* 2 bytes */
+#define PCDATA_CODE_TYPE	0x0014
+#define PCDATA_INDICATOR	0x0015
+
+typedef struct cb_config_t {
+    u_int		size[7];
+    struct pci_dev	dev;
+} cb_config_t;
+
+#define BASE(dev,n)	((dev).resource[n].start)
+#define ROM(dev)	((dev).resource[6].start)
+
+/* There are three classes of bridge maps: IO ports,
+   non-prefetchable memory, and prefetchable memory */
+typedef enum { B_IO, B_M1, B_M2 } bridge_type;
+
+/*=====================================================================
+
+    Expansion ROM's have a special layout, and pointers specify an
+    image number and an offset within that image.  check_rom()
+    verifies that the expansion ROM exists and has the standard
+    layout.  xlate_rom_addr() converts an image/offset address to an
+    absolute offset from the ROM's base address.
+    
+=====================================================================*/
+
+static int check_rom(u_char *b, u_long len)
+{
+    u_int img = 0, ofs = 0, sz;
+    u_short data;
+    DEBUG(0, "ROM image dump:\n");
+    while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) {
+	data = readb(b+ROM_DATA_PTR) +
+	    (readb(b+ROM_DATA_PTR+1) << 8);
+	sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) +
+		    (readb(b+data+PCDATA_IMAGE_SZ+1) << 8));
+	DEBUG(0, "  image %d: 0x%06x-0x%06x, signature %c%c%c%c\n",
+	      img, ofs, ofs+sz-1,
+	      readb(b+data+PCDATA_SIGNATURE),
+	      readb(b+data+PCDATA_SIGNATURE+1),
+	      readb(b+data+PCDATA_SIGNATURE+2),
+	      readb(b+data+PCDATA_SIGNATURE+3));
+	ofs += sz; img++;
+	if ((readb(b+data+PCDATA_INDICATOR) & 0x80) ||
+	    (sz == 0) || (ofs >= len)) break;
+	b += sz;
+    }
+    return img;
+}
+
+static u_int xlate_rom_addr(u_char *b, u_int addr)
+{
+    u_int img = 0, ofs = 0, sz;
+    u_short data;
+    while ((readb(b) == 0x55) && (readb(b+1) == 0xaa)) {
+	if (img == (addr >> 28))
+	    return (addr & 0x0fffffff) + ofs;
+	data = readb(b+ROM_DATA_PTR) + (readb(b+ROM_DATA_PTR+1) << 8);
+	sz = 512 * (readb(b+data+PCDATA_IMAGE_SZ) +
+		    (readb(b+data+PCDATA_IMAGE_SZ+1) << 8));
+	if ((sz == 0) || (readb(b+data+PCDATA_INDICATOR) & 0x80))
+	    break;
+	b += sz; ofs += sz; img++;
+    }
+    return 0;
+}
+
+/*=====================================================================
+
+    These are similar to setup_cis_mem and release_cis_mem for 16-bit
+    cards.  The "result" that is used externally is the cb_cis_virt
+    pointer in the socket_info_t structure.
+    
+=====================================================================*/
+
+int cb_setup_cis_mem(socket_info_t *s, int space)
+{
+    cb_bridge_map *m = &s->cb_cis_map;
+    u_long base = 0;
+    u_int sz, br;
+
+    if (space == s->cb_cis_space)
+	return CS_SUCCESS;
+    else if (s->cb_cis_space != 0)
+	cb_release_cis_mem(s);
+    DEBUG(1, "cs: cb_setup_cis_mem(space %d)\n", space);
+    /* If socket is configured, then use existing memory mapping */
+    if (s->lock_count) {
+	s->cb_cis_virt =
+	    ioremap(BASE(s->cb_config[0].dev, space-1),
+		    s->cb_config[0].size[space-1] & ~3);
+	s->cb_cis_space = space;
+	return CS_SUCCESS;
+    }
+    
+    /* Not configured?  Then set up temporary map */
+    br = (space == 7) ? CB_ROM_BASE : CB_BAR(space-1);
+    pci_writel(s->cap.cardbus, 0, br, 0xffffffff);
+    pci_readl(s->cap.cardbus, 0, br, &sz);
+    sz &= PCI_BASE_ADDRESS_MEM_MASK;
+    sz = FIND_FIRST_BIT(sz);
+    if (sz < PAGE_SIZE) sz = PAGE_SIZE;
+    if (find_mem_region(&base, sz, "cb_enabler", sz, 0) != 0) {
+	printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+	       " CardBus socket %d\n", sz/1024, s->sock);
+	return CS_OUT_OF_RESOURCE;
+    }
+    s->cb_cis_space = space;
+    s->cb_cis_virt = ioremap(base, sz);
+    DEBUG(1, "  phys 0x%08lx-0x%08lx, virt 0x%08lx\n",
+	  base, base+sz-1, (u_long)s->cb_cis_virt);
+    pci_writel(s->cap.cardbus, 0, br, base | 1);
+    pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, PCI_COMMAND_MEMORY);
+    m->map = 0; m->flags = MAP_ACTIVE;
+    m->start = base; m->stop = base+sz-1;
+    s->ss_entry(s->sock, SS_SetBridge, m);
+    if ((space == 7) && (check_rom(s->cb_cis_virt, sz) == 0)) {
+	printk(KERN_NOTICE "cs: no valid ROM images found!\n");
+	return CS_READ_FAILURE;
+    }
+    return CS_SUCCESS;
+}
+
+void cb_release_cis_mem(socket_info_t *s)
+{
+    cb_bridge_map *m = &s->cb_cis_map;
+    u_int br;
+    if (s->cb_cis_virt) {
+	DEBUG(1, "cs: cb_release_cis_mem()\n");
+	iounmap(s->cb_cis_virt);
+	s->cb_cis_virt = NULL;
+	s->cb_cis_space = 0;
+    }
+    if (m->start) {
+	/* This is overkill: we probably only need to release the
+	   memory region, but the rest should be safe */
+	br = (s->cb_cis_space == 7) ?
+	    CB_ROM_BASE : CB_BAR(s->cb_cis_space-1);
+	m->map = 0; m->flags = 0;
+	s->ss_entry(s->sock, SS_SetBridge, m);
+	pci_writeb(s->cap.cardbus, 0, PCI_COMMAND, 0);
+	pci_writel(s->cap.cardbus, 0, br, 0);
+	release_mem_region(m->start, m->stop - m->start + 1);
+	m->start = 0;
+    }
+}
+
+/*=====================================================================
+
+    This is used by the CIS processing code to read CIS information
+    from a CardBus device.
+    
+=====================================================================*/
+
+void read_cb_mem(socket_info_t *s, u_char fn, int space,
+		 u_int addr, u_int len, void *ptr)
+{
+    DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len);
+    if (space == 0) {
+	if (addr+len > 0x100) goto fail;
+	for (; len; addr++, ptr++, len--)
+	    pci_readb(s->cap.cardbus, fn, addr, (u_char *)ptr);
+    } else {
+	if (cb_setup_cis_mem(s, space) != 0) goto fail;
+	if (space == 7) {
+	    addr = xlate_rom_addr(s->cb_cis_virt, addr);
+	    if (addr == 0) goto fail;
+	}
+	if (addr+len > s->cb_cis_map.stop - s->cb_cis_map.start)
+	    goto fail;
+	if (s->cb_cis_virt != NULL)
+	    for (; len; addr++, ptr++, len--)
+		*(u_char *)ptr = readb(s->cb_cis_virt+addr);
+    }
+    return;
+ fail:
+    memset(ptr, 0xff, len);
+    return;
+}
+
+/*=====================================================================
+
+    cb_alloc() and cb_free() allocate and free the kernel data
+    structures for a Cardbus device, and handle the lowest level PCI
+    device setup issues.
+    
+=====================================================================*/
+
+int cb_alloc(socket_info_t *s)
+{
+    struct pci_dev tmp;
+    u_short vend, v, dev;
+    u_char i, hdr, fn, bus = s->cap.cardbus;
+    cb_config_t *c;
+
+    tmp.bus = s->cap.cb_bus; tmp.devfn = 0;
+    tmp.next = pci_devices; pci_devices = &tmp;
+
+    pci_readw(bus, 0, PCI_VENDOR_ID, &vend);
+    pci_readw(bus, 0, PCI_DEVICE_ID, &dev);
+    printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, "
+	   "device 0x%04x\n", bus, vend, dev);
+
+    pci_readb(bus, 0, PCI_HEADER_TYPE, &hdr);
+    if (hdr & 0x80) {
+	/* Count functions */
+	for (fn = 0; fn < 8; fn++) {
+	    tmp.devfn = fn;
+	    pci_readw(bus, fn, PCI_VENDOR_ID, &v);
+	    if (v != vend) break;
+	}
+    } else fn = 1;
+    s->functions = fn;
+    
+    c = kmalloc(fn * sizeof(struct cb_config_t), GFP_ATOMIC);
+    if (!c) return CS_OUT_OF_RESOURCE;
+    memset(c, 0, fn * sizeof(struct cb_config_t));
+    s->cb_config = c;
+
+    pci_devices = tmp.next;
+    for (i = 0; i < fn; i++) {
+	c[i].dev.bus = s->cap.cb_bus;
+	c[i].dev.devfn = i;
+	if (i < fn-1) {
+	    c[i].dev.sibling = c[i].dev.next = &c[i+1].dev;
+	}
+    }
+    s->cap.cb_bus->devices = &c[0].dev;
+    /* Link into PCI device chain */
+    c[s->functions-1].dev.next = pci_devices;
+    pci_devices = &c[0].dev;
+    for (i = 0; i < fn; i++) {
+	c[i].dev.vendor = vend;
+	pci_readw(bus, i, PCI_DEVICE_ID, &c[i].dev.device);
+	pci_readl(bus, i, PCI_CLASS_REVISION, &c[i].dev.class);
+	c[i].dev.class >>= 8;
+	c[i].dev.hdr_type = hdr;
+	pci_proc_attach_device(&c[i].dev);
+    }
+    
+    return CS_SUCCESS;
+}
+
+void cb_free(socket_info_t *s)
+{
+    struct pci_dev **p, *q;
+    cb_config_t *c = s->cb_config;
+
+    if (c) {
+	/* Unlink from PCI device chain */
+	for (p = &pci_devices; *p; p = &((*p)->next))
+	    if (*p == &c[0].dev) break;
+	for (q = *p; q; q = q->next) {
+	    if (q->bus != (*p)->bus) break;
+	    pci_proc_detach_device(q);
+	}
+	if (*p) *p = q;
+	s->cap.cb_bus->devices = NULL;
+    }
+    printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cardbus);
+    if (s->cb_config) {
+	kfree(s->cb_config);
+	s->cb_config = NULL;
+    }
+}
+
+/*=====================================================================
+
+    cb_config() has the job of allocating all system resources that
+    a Cardbus card requires.  Rather than using the CIS (which seems
+    to not always be present), it treats the card as an ordinary PCI
+    device, and probes the base address registers to determine each
+    function's IO and memory space needs.
+
+    It is called from the RequestIO card service.
+    
+======================================================================*/
+
+int cb_config(socket_info_t *s)
+{
+    cb_config_t *c = s->cb_config;
+    u_char fn = s->functions;
+    u_char i, j, bus = s->cap.cardbus, *name;
+    u_int sz, align, m, mask[3], num[3], base[3];
+    int irq, try, ret;
+
+    printk(KERN_INFO "cs: cb_config(bus %d)\n", s->cap.cardbus);
+
+    /* Determine IO and memory space needs */
+    num[B_IO] = num[B_M1] = num[B_M2] = 0;
+    mask[B_IO] = mask[B_M1] = mask[B_M2] = 0;
+    for (i = 0; i < fn; i++) {
+	for (j = 0; j < 6; j++) {
+	    pci_writel(bus, i, CB_BAR(j), 0xffffffff);
+	    pci_readl(bus, i, CB_BAR(j), &sz);
+	    if (sz == 0) continue;
+	    if (sz & PCI_BASE_ADDRESS_SPACE) {
+		m = B_IO;
+		sz &= PCI_BASE_ADDRESS_IO_MASK;
+	    } else {
+		m = (sz & PCI_BASE_ADDRESS_MEM_PREFETCH) ? B_M2 : B_M1;
+		sz &= PCI_BASE_ADDRESS_MEM_MASK;
+	    }
+	    sz = FIND_FIRST_BIT(sz);
+	    c[i].size[j] = sz | m;
+	    if (m && (sz < PAGE_SIZE)) sz = PAGE_SIZE;
+	    num[m] += sz; mask[m] |= sz;
+	}
+	pci_writel(bus, i, CB_ROM_BASE, 0xffffffff);
+	pci_readl(bus, i, CB_ROM_BASE, &sz);
+	if (sz != 0) {
+	    sz = FIND_FIRST_BIT(sz & ~0x00000001);
+	    c[i].size[6] = sz | B_M1;
+	    if (sz < PAGE_SIZE) sz = PAGE_SIZE;
+	    num[B_M1] += sz; mask[B_M1] |= sz;
+	}
+    }
+
+    /* Allocate system resources */
+    name = "cb_enabler";
+    s->io[0].NumPorts = num[B_IO];
+    s->io[0].BasePort = 0;
+    if (num[B_IO]) {
+	if (find_io_region(&s->io[0].BasePort, num[B_IO], name) != 0) {
+	    printk(KERN_NOTICE "cs: could not allocate %d IO ports for"
+		   " CardBus socket %d\n", num[B_IO], s->sock);
+	    goto failed;
+	}
+	base[B_IO] = s->io[0].BasePort + num[B_IO];
+    }
+    s->win[0].size = num[B_M1];
+    s->win[0].base = 0;
+    if (num[B_M1]) {
+	if (find_mem_region(&s->win[0].base, num[B_M1],
+			    name, num[B_M1], 0) != 0) {
+	    printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+		   " CardBus socket %d\n", num[B_M1]/1024, s->sock);
+	    goto failed;
+	}
+	base[B_M1] = s->win[0].base + num[B_M1];
+    }
+    s->win[1].size = num[B_M2];
+    s->win[1].base = 0;
+    if (num[B_M2]) {
+	if (find_mem_region(&s->win[1].base, num[B_M2],
+			    name, num[B_M2], 0) != 0) {
+	    printk(KERN_NOTICE "cs: could not allocate %dK memory for"
+		   " CardBus socket %d\n", num[B_M2]/1024, s->sock);
+	    goto failed;
+	}
+	base[B_M2] = s->win[1].base + num[B_M2];
+    }
+    
+    /* Set up base address registers */
+    while (mask[B_IO] | mask[B_M1] | mask[B_M2]) {
+	num[B_IO] = FIND_FIRST_BIT(mask[B_IO]); mask[B_IO] -= num[B_IO];
+	num[B_M1] = FIND_FIRST_BIT(mask[B_M1]); mask[B_M1] -= num[B_M1];
+	num[B_M2] = FIND_FIRST_BIT(mask[B_M2]); mask[B_M2] -= num[B_M2];
+	for (i = 0; i < fn; i++) {
+	    for (j = 0; j < 7; j++) {
+		sz = c[i].size[j];
+		m = sz & 3; sz &= ~3;
+		align = (m && (sz < PAGE_SIZE)) ? PAGE_SIZE : sz;
+		if (sz && (align == num[m])) {
+		    base[m] -= align;
+		    if (j < 6)
+			printk(KERN_INFO "  fn %d bar %d: ", i, j+1);
+		    else
+			printk(KERN_INFO "  fn %d rom: ", i);
+		    printk("%s 0x%x-0x%x\n", (m) ? "mem" : "io",
+			   base[m], base[m]+sz-1);
+		    BASE(c[i].dev, j) = base[m];
+		}
+	    }
+	}
+    }
+    
+    /* Allocate interrupt if needed */
+    s->irq.AssignedIRQ = irq = 0; ret = -1;
+    for (i = 0; i < fn; i++) {
+	pci_readb(bus, i, PCI_INTERRUPT_PIN, &j);
+	if (j == 0) continue;
+	if (irq == 0) {
+	    if (s->cap.irq_mask & (1 << s->cap.pci_irq)) {
+		irq = s->cap.pci_irq;
+		ret = 0;
+	    }
+#ifdef CONFIG_ISA
+	    else
+		for (try = 0; try < 2; try++) {
+		    for (irq = 0; irq < 32; irq++)
+			if ((s->cap.irq_mask >> irq) & 1) {
+			    ret = try_irq(IRQ_TYPE_EXCLUSIVE, irq, try);
+			    if (ret == 0) break;
+			}
+		    if (ret == 0) break;
+		}
+	    if (ret != 0) {
+		printk(KERN_NOTICE "cs: could not allocate interrupt"
+		       " for CardBus socket %d\n", s->sock);
+		goto failed;
+	    }
+#endif
+	    s->irq.AssignedIRQ = irq;
+	}
+    }
+    c[0].dev.irq = irq;
+    
+    return CS_SUCCESS;
+
+failed:
+    cb_release(s);
+    return CS_OUT_OF_RESOURCE;
+}
+
+/*======================================================================
+
+    cb_release() releases all the system resources (IO and memory
+    space, and interrupt) committed for a Cardbus card by a prior call
+    to cb_config().
+
+    It is called from the ReleaseIO() service.
+    
+======================================================================*/
+
+void cb_release(socket_info_t *s)
+{
+    cb_config_t *c = s->cb_config;
+    
+    DEBUG(0, "cs: cb_release(bus %d)\n", s->cap.cardbus);
+    
+    if (s->win[0].size > 0)
+	release_mem_region(s->win[0].base, s->win[0].size);
+    if (s->win[1].size > 0)
+	release_mem_region(s->win[1].base, s->win[1].size);
+    if (s->io[0].NumPorts > 0)
+	release_region(s->io[0].BasePort, s->io[0].NumPorts);
+    s->io[0].NumPorts = 0;
+#ifdef CONFIG_ISA
+    if ((c[0].dev.irq != 0) && (c[0].dev.irq != s->cap.pci_irq))
+	undo_irq(IRQ_TYPE_EXCLUSIVE, c[0].dev.irq);
+#endif
+}
+
+/*=====================================================================
+
+    cb_enable() has the job of configuring a socket for a Cardbus
+    card, and initializing the card's PCI configuration registers.
+
+    It first sets up the Cardbus bridge windows, for IO and memory
+    accesses.  Then, it initializes each card function's base address
+    registers, interrupt line register, and command register.
+
+    It is called as part of the RequestConfiguration card service.
+    It should be called after a previous call to cb_config() (via the
+    RequestIO service).
+    
+======================================================================*/
+
+void cb_enable(socket_info_t *s)
+{
+    u_char i, j, bus = s->cap.cardbus;
+    cb_config_t *c = s->cb_config;
+    
+    DEBUG(0, "cs: cb_enable(bus %d)\n", bus);
+    
+    /* Configure bridge */
+    if (s->cb_cis_map.start)
+	cb_release_cis_mem(s);
+    for (i = 0; i < 3; i++) {
+	cb_bridge_map m;
+	switch (i) {
+	case B_IO:
+	    m.map = 0; m.flags = MAP_IOSPACE | MAP_ACTIVE;
+	    m.start = s->io[0].BasePort;
+	    m.stop = m.start + s->io[0].NumPorts - 1;
+	    break;
+	case B_M1:
+	    m.map = 0; m.flags = MAP_ACTIVE;
+	    m.start = s->win[0].base;
+	    m.stop = m.start + s->win[0].size - 1;
+	    break;
+	case B_M2:
+	    m.map = 1; m.flags = MAP_PREFETCH | MAP_ACTIVE;
+	    m.start = s->win[1].base;
+	    m.stop = m.start + s->win[1].size - 1;
+	    break;
+	}
+	if (m.start == 0) continue;
+	DEBUG(0, "  bridge %s map %d (flags 0x%x): 0x%x-0x%x\n",
+	      (m.flags & MAP_IOSPACE) ? "io" : "mem",
+	      m.map, m.flags, m.start, m.stop);
+	s->ss_entry(s->sock, SS_SetBridge, &m);
+    }
+
+    /* Set up base address registers */
+    for (i = 0; i < s->functions; i++) {
+	for (j = 0; j < 6; j++) {
+	    if (BASE(c[i].dev, j) != 0)
+		pci_writel(bus, i, CB_BAR(j), BASE(c[i].dev, j));
+	}
+	if (ROM(c[i].dev) != 0)
+	    pci_writel(bus, i, CB_ROM_BASE, ROM(c[i].dev) | 1);
+    }
+
+    /* Set up PCI interrupt and command registers */
+    for (i = 0; i < s->functions; i++) {
+	pci_writeb(bus, i, PCI_COMMAND, PCI_COMMAND_MASTER |
+		   PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_writeb(bus, i, PCI_CACHE_LINE_SIZE, 8);
+    }
+    
+    if (s->irq.AssignedIRQ) {
+	for (i = 0; i < s->functions; i++)
+	    pci_writeb(bus, i, PCI_INTERRUPT_LINE,
+		       s->irq.AssignedIRQ);
+	s->socket.io_irq = s->irq.AssignedIRQ;
+	s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    }
+}
+
+/*======================================================================
+
+    cb_disable() unconfigures a Cardbus card previously set up by
+    cb_enable().
+
+    It is called from the ReleaseConfiguration service.
+    
+======================================================================*/
+
+void cb_disable(socket_info_t *s)
+{
+    u_char i;
+    cb_bridge_map m = { 0, 0, 0, 0xffff };
+    
+    DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cardbus);
+    
+    /* Turn off bridge windows */
+    if (s->cb_cis_map.start)
+	cb_release_cis_mem(s);
+    for (i = 0; i < 3; i++) {
+	switch (i) {
+	case B_IO: m.map = 0; m.flags = MAP_IOSPACE; break;
+	case B_M1: m.map = m.flags = 0; break;
+	case B_M2: m.map = 1; m.flags = 0; break;
+	}
+	s->ss_entry(s->sock, SS_SetBridge, &m);
+    }
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cb_enabler.c linux/drivers/pcmcia/cb_enabler.c
--- v2.3.16/linux/drivers/pcmcia/cb_enabler.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/cb_enabler.c	Fri Sep  3 13:49:12 1999
@@ -0,0 +1,405 @@
+/*======================================================================
+
+    Cardbus device enabler
+
+    cb_enabler.c 1.21 1999/08/28 04:01:45
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+    The general idea:
+
+    A client driver registers using register_driver().  This module
+    then creates a Card Services pseudo-client and registers it, and
+    configures the socket if this is the first client.  It then
+    invokes the appropriate PCI client routines in response to Card
+    Services events.  
+
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"cb_enabler.c 1.21 1999/08/28 04:01:45 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+    dev_link_t		*(*attach)(void);
+    dev_info_t		dev_info;
+    driver_operations	*ops;
+    dev_link_t		*dev_list;
+} driver_info_t;
+
+static dev_link_t *cb_attach(int n);
+#define MK_ENTRY(fn, n) \
+static dev_link_t *fn(void) { return cb_attach(n); }
+
+#define MAX_DRIVER	4
+
+MK_ENTRY(attach_0, 0);
+MK_ENTRY(attach_1, 1);
+MK_ENTRY(attach_2, 2);
+MK_ENTRY(attach_3, 3);
+
+static driver_info_t driver[4] = {
+    { attach_0 }, { attach_1 }, { attach_2 }, { attach_3 }
+};
+
+typedef struct bus_info_t {
+    u_char		bus;
+    int			flags, ncfg, nuse;
+    dev_link_t		*owner;
+} bus_info_t;
+
+#define DID_REQUEST	1
+#define DID_CONFIG	2
+
+static void cb_release(u_long arg);
+static int cb_event(event_t event, int priority,
+		    event_callback_args_t *args);
+
+static void cb_detach(dev_link_t *);
+
+static bus_info_t bus_table[MAX_DRIVER];
+
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+struct dev_link_t *cb_attach(int n)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int ret;
+    
+    DEBUG(0, "cb_attach(%d)\n", n);
+
+    MOD_INC_USE_COUNT;
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &cb_release;
+    link->release.data = (u_long)link;
+
+    link->conf.IntType = INT_CARDBUS;
+    link->conf.Vcc = 33;
+
+    /* Insert into instance chain for this driver */
+    link->priv = &driver[n];
+    link->next = driver[n].dev_list;
+    driver[n].dev_list = link;
+    
+    /* Register with Card Services */
+    client_reg.dev_info = &driver[n].dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.event_handler = &cb_event;
+    client_reg.EventMask =
+	CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	cb_detach(link);
+	return NULL;
+    }
+    return link;
+}
+
+/*====================================================================*/
+
+static void cb_detach(dev_link_t *link)
+{
+    driver_info_t *dev = link->priv;
+    dev_link_t **linkp;
+    bus_info_t *b = (void *)link->win;
+    u_long flags;
+    
+    DEBUG(0, "cb_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev->dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    save_flags(flags);
+    cli();
+    if (link->state & DEV_RELEASE_PENDING) {
+	del_timer(&link->release);
+	link->state &= ~DEV_RELEASE_PENDING;
+    }
+    restore_flags(flags);
+    
+    if (link->state & DEV_CONFIG)
+	cb_release((u_long)link);
+    
+    /* Don't drop Card Services connection if we are the bus owner */
+    if ((b->flags != 0) && (link == b->owner)) {
+	link->state |= DEV_STALE_LINK;
+	return;
+    }
+    
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    *linkp = link->next;
+    kfree_s(link, sizeof(struct dev_link_t));
+    MOD_DEC_USE_COUNT;
+}
+
+/*====================================================================*/
+
+static void cb_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    driver_info_t *drv = link->priv;
+    dev_locator_t loc;
+    bus_info_t *b;
+    config_info_t config;
+    u_char bus, devfn;
+    int i;
+    
+    DEBUG(0, "cb_config(0x%p)\n", link);
+    link->state |= DEV_CONFIG;
+
+    /* Get PCI bus info */
+    CardServices(GetConfigurationInfo, handle, &config);
+    bus = config.Option; devfn = config.Function;
+
+    /* Is this a new bus? */
+    for (i = 0; i < MAX_DRIVER; i++)
+	if (bus == bus_table[i].bus) break;
+    if (i == MAX_DRIVER) {
+	for (i = 0; i < MAX_DRIVER; i++)
+	    if (bus_table[i].bus == 0) break;
+	b = &bus_table[i]; link->win = (void *)b;
+	b->bus = bus;
+	b->flags = 0;
+	b->ncfg = b->nuse = 1;
+
+	/* Special hook: CS know what to do... */
+	i = CardServices(RequestIO, handle, NULL);
+	if (i != CS_SUCCESS) {
+	    cs_error(handle, RequestIO, i);
+	    return;
+	}
+	b->flags |= DID_REQUEST;
+	b->owner = link;
+	i = CardServices(RequestConfiguration, handle, &link->conf);
+	if (i != CS_SUCCESS) {
+	    cs_error(handle, RequestConfiguration, i);
+	    return;
+	}
+	b->flags |= DID_CONFIG;
+    } else {
+	b = &bus_table[i]; link->win = (void *)b;
+	if (b->flags & DID_CONFIG) {
+	    b->ncfg++; b->nuse++;
+	}
+    }
+    loc.bus = LOC_PCI;
+    loc.b.pci.bus = bus;
+    loc.b.pci.devfn = devfn;
+    link->dev = drv->ops->attach(&loc);
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+}
+
+/*====================================================================*/
+
+static void cb_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    driver_info_t *drv = link->priv;
+    bus_info_t *b = (void *)link->win;
+
+    DEBUG(0, "cb_release(0x%p)\n", link);
+
+    if (link->dev != NULL) {
+	drv->ops->detach(link->dev);
+	link->dev = NULL;
+    }
+    if (link->state & DEV_CONFIG) {
+	/* If we're suspended, config was already released */
+	if (link->state & DEV_SUSPEND)
+	    b->flags &= ~DID_CONFIG;
+	else if ((b->flags & DID_CONFIG) && (--b->ncfg == 0)) {
+	    CardServices(ReleaseConfiguration, b->owner->handle,
+			 &b->owner->conf);
+	    b->flags &= ~DID_CONFIG;
+	}
+	if ((b->flags & DID_REQUEST) && (--b->nuse == 0)) {
+	    CardServices(ReleaseIO, b->owner->handle, NULL);
+	    b->flags &= ~DID_REQUEST;
+	}
+	if (b->flags == 0) {
+	    if (b->owner && (b->owner->state & DEV_STALE_LINK))
+		cb_detach(b->owner);
+	    b->bus = 0; b->owner = NULL;
+	}
+    }
+    link->state &= ~DEV_CONFIG;
+}
+
+/*====================================================================*/
+
+static int cb_event(event_t event, int priority,
+		    event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    driver_info_t *drv = link->priv;
+    bus_info_t *b = (void *)link->win;
+    
+    DEBUG(0, "cb_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    link->release.expires = jiffies + HZ/20;
+	    link->state |= DEV_RELEASE_PENDING;
+	    add_timer(&link->release);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	cb_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG) {
+	    if (drv->ops->suspend != NULL)
+		drv->ops->suspend(link->dev);
+	    b->ncfg--;
+	    if (b->ncfg == 0)
+		CardServices(ReleaseConfiguration, link->handle,
+			     &link->conf);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    b->ncfg++;
+	    if (b->ncfg == 1)
+		CardServices(RequestConfiguration, link->handle,
+			     &link->conf);
+	    if (drv->ops->resume != NULL)
+		drv->ops->resume(link->dev);
+	}
+	break;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+int register_driver(struct driver_operations *ops)
+{
+    int i;
+    
+    DEBUG(0, "register_driver('%s')\n", ops->name);
+
+    for (i = 0; i < MAX_DRIVER; i++)
+	if (driver[i].ops == NULL) break;
+    if (i == MAX_DRIVER)
+	return -1;
+
+    MOD_INC_USE_COUNT;
+    driver[i].ops = ops;
+    strcpy(driver[i].dev_info, ops->name);
+    register_pccard_driver(&driver[i].dev_info, driver[i].attach,
+			   &cb_detach);
+    return 0;
+}
+
+void unregister_driver(struct driver_operations *ops)
+{
+    int i;
+
+    DEBUG(0, "unregister_driver('%s')\n", ops->name);
+    for (i = 0; i < MAX_DRIVER; i++)
+	if (driver[i].ops == ops) break;
+    if (i < MAX_DRIVER) {
+	unregister_pccard_driver(&driver[i].dev_info);
+	driver[i].ops = NULL;
+	MOD_DEC_USE_COUNT;
+    }
+}
+
+/*====================================================================*/
+
+int init_module(void) {
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "cb_enabler: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    return 0;
+}
+
+void cleanup_module(void) {
+    DEBUG(0, "cb_enabler: unloading\n");
+}
+
+/*====================================================================*/
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cirrus.h linux/drivers/pcmcia/cirrus.h
--- v2.3.16/linux/drivers/pcmcia/cirrus.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/cirrus.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,157 @@
+/*
+ * cirrus.h 1.3 1999/08/28 04:01:46
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CIRRUS_H
+#define _LINUX_CIRRUS_H
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS		0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6729
+#define PCI_DEVICE_ID_CIRRUS_6729	0x1100
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_6832
+#define PCI_DEVICE_ID_CIRRUS_6832	0x1110
+#endif
+
+#define PD67_MISC_CTL_1		0x16	/* Misc control 1 */
+#define PD67_FIFO_CTL		0x17	/* FIFO control */
+#define PD67_MISC_CTL_2		0x1E	/* Misc control 2 */
+#define PD67_CHIP_INFO		0x1f	/* Chip information */
+#define PD67_ATA_CTL		0x026	/* 6730: ATA control */
+#define PD67_EXT_INDEX		0x2e	/* Extension index */
+#define PD67_EXT_DATA		0x2f	/* Extension data */
+
+/* PD6722 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_DATA_MASK0		0x01	/* Data mask 0 */
+#define PD67_DATA_MASK1		0x02	/* Data mask 1 */
+#define PD67_DMA_CTL		0x03	/* DMA control */
+
+/* PD6730 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD67_EXT_CTL_1		0x03	/* Extension control 1 */
+#define PD67_MEM_PAGE(n)	((n)+5)	/* PCI window bits 31:24 */
+#define PD67_EXTERN_DATA	0x0a
+#define PD67_MISC_CTL_3		0x25
+#define PD67_SMB_PWR_CTL	0x26
+
+/* I/O window address offset */
+#define PD67_IO_OFF(w)		(0x36+((w)<<1))
+
+/* Timing register sets */
+#define PD67_TIME_SETUP(n)	(0x3a + 3*(n))
+#define PD67_TIME_CMD(n)	(0x3b + 3*(n))
+#define PD67_TIME_RECOV(n)	(0x3c + 3*(n))
+
+/* Flags for PD67_MISC_CTL_1 */
+#define PD67_MC1_5V_DET		0x01	/* 5v detect */
+#define PD67_MC1_MEDIA_ENA	0x01	/* 6730: Multimedia enable */
+#define PD67_MC1_VCC_3V		0x02	/* 3.3v Vcc */
+#define PD67_MC1_PULSE_MGMT	0x04
+#define PD67_MC1_PULSE_IRQ	0x08
+#define PD67_MC1_SPKR_ENA	0x10
+#define PD67_MC1_INPACK_ENA	0x80
+
+/* Flags for PD67_FIFO_CTL */
+#define PD67_FIFO_EMPTY		0x80
+
+/* Flags for PD67_MISC_CTL_2 */
+#define PD67_MC2_FREQ_BYPASS	0x01
+#define PD67_MC2_DYNAMIC_MODE	0x02
+#define PD67_MC2_SUSPEND	0x04
+#define PD67_MC2_5V_CORE	0x08
+#define PD67_MC2_LED_ENA	0x10	/* IRQ 12 is LED enable */
+#define PD67_MC2_FAST_PCI	0x10	/* 6729: PCI bus > 25 MHz */
+#define PD67_MC2_3STATE_BIT7	0x20	/* Floppy change bit */
+#define PD67_MC2_DMA_MODE	0x40
+#define PD67_MC2_IRQ15_RI	0x80	/* IRQ 15 is ring enable */
+
+/* Flags for PD67_CHIP_INFO */
+#define PD67_INFO_SLOTS		0x20	/* 0 = 1 slot, 1 = 2 slots */
+#define PD67_INFO_CHIP_ID	0xc0
+#define PD67_INFO_REV		0x1c
+
+/* Fields in PD67_TIME_* registers */
+#define PD67_TIME_SCALE		0xc0
+#define PD67_TIME_SCALE_1	0x00
+#define PD67_TIME_SCALE_16	0x40
+#define PD67_TIME_SCALE_256	0x80
+#define PD67_TIME_SCALE_4096	0xc0
+#define PD67_TIME_MULT		0x3f
+
+/* Fields in PD67_DMA_CTL */
+#define PD67_DMA_MODE		0xc0
+#define PD67_DMA_OFF		0x00
+#define PD67_DMA_DREQ_INPACK	0x40
+#define PD67_DMA_DREQ_WP	0x80
+#define PD67_DMA_DREQ_BVD2	0xc0
+#define PD67_DMA_PULLUP		0x20	/* Disable socket pullups? */
+
+/* Fields in PD67_EXT_CTL_1 */
+#define PD67_EC1_VCC_PWR_LOCK	0x01
+#define PD67_EC1_AUTO_PWR_CLEAR	0x02
+#define PD67_EC1_LED_ENA	0x04
+#define PD67_EC1_INV_CARD_IRQ	0x08
+#define PD67_EC1_INV_MGMT_IRQ	0x10
+#define PD67_EC1_PULLUP_CTL	0x20
+
+/* Fields in PD67_MISC_CTL_3 */
+#define PD67_MC3_IRQ_MASK	0x03
+#define PD67_MC3_IRQ_PCPCI	0x00
+#define PD67_MC3_IRQ_EXTERN	0x01
+#define PD67_MC3_IRQ_PCIWAY	0x02
+#define PD67_MC3_IRQ_PCI	0x03
+#define PD67_MC3_PWR_MASK	0x0c
+#define PD67_MC3_PWR_SERIAL	0x00
+#define PD67_MC3_PWR_TI2202	0x08
+#define PD67_MC3_PWR_SMB	0x0c
+
+/* Register definitions for Cirrus PD6832 PCI-to-CardBus bridge */
+
+/* PD6832 extension registers -- indexed in PD67_EXT_INDEX */
+#define PD68_EXT_CTL_2			0x0b
+#define PD68_PCI_SPACE			0x22
+#define PD68_PCCARD_SPACE		0x23
+#define PD68_WINDOW_TYPE		0x24
+#define PD68_EXT_CSC			0x2e
+#define PD68_MISC_CTL_4			0x2f
+#define PD68_MISC_CTL_5			0x30
+#define PD68_MISC_CTL_6			0x31
+
+/* Extra flags in PD67_MISC_CTL_3 */
+#define PD68_MC3_HW_SUSP		0x10
+#define PD68_MC3_MM_EXPAND		0x40
+#define PD68_MC3_MM_ARM			0x80
+
+/* Bridge Control Register */
+#define  PD6832_BCR_MGMT_IRQ_ENA	0x0800
+
+/* Socket Number Register */
+#define PD6832_SOCKET_NUMBER		0x004c	/* 8 bit */
+
+#endif /* _LINUX_CIRRUS_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cistpl.c linux/drivers/pcmcia/cistpl.c
--- v2.3.16/linux/drivers/pcmcia/cistpl.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/cistpl.c	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,1394 @@
+/*======================================================================
+
+    PCMCIA Card Information Structure parser
+
+    cistpl.c 1.70 1999/09/07 15:18:58
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bus_ops.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+#define MIN(a, b)		(((a) < (b)) ? (a) : (b))
+
+static const u_char mantissa[] = {
+    10, 12, 13, 15, 20, 25, 30, 35,
+    40, 45, 50, 55, 60, 70, 80, 90
+};
+
+static const u_int exponent[] = {
+    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
+};
+
+/* Convert an extended speed byte to a time in nanoseconds */
+#define SPEED_CVT(v) \
+    (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
+/* Convert a power byte to a current in 0.1 microamps */
+#define POWER_CVT(v) \
+    (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
+#define POWER_SCALE(v)		(exponent[(v)&7])
+
+/* Upper limit on reasonable # of tuples */
+#define MAX_TUPLES		200
+
+/*======================================================================
+
+    Low-level functions to read and write CIS memory.  I think the
+    write routine is only useful for writing one-byte registers.
+    
+======================================================================*/
+
+void read_cis_mem(socket_info_t *s, int attr, u_int addr,
+		  u_int len, void *ptr)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    u_char *sys;
+    u_int inc = 1;
+    
+    DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    if (setup_cis_mem(s) != 0) {
+	memset(ptr, 0xff, len);
+	return;
+    }
+    mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB;
+    if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+    mem->card_start = addr & ~(s->cap.map_size-1);
+
+    for (; len > 0; sys = s->cis_virt) {
+	s->ss_entry(s->sock, SS_SetMemMap, mem);
+	DEBUG(3,  "cs:  %#2.2x %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+	      bus_readb(s->cap.bus, sys),
+	      bus_readb(s->cap.bus, sys+inc),
+	      bus_readb(s->cap.bus, sys+2*inc),
+	      bus_readb(s->cap.bus, sys+3*inc),
+	      bus_readb(s->cap.bus, sys+4*inc));
+	for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
+	    if (sys == s->cis_virt+s->cap.map_size) break;
+	    *(u_char *)ptr = bus_readb(s->cap.bus, sys);
+	}
+	mem->card_start += s->cap.map_size;
+    }
+}
+
+void write_cis_mem(socket_info_t *s, int attr, u_int addr,
+		   u_int len, void *ptr)
+{
+    pccard_mem_map *mem = &s->cis_mem;
+    u_char *sys;
+    int inc = 1;
+    
+    DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    if (setup_cis_mem(s) != 0) return;
+    mem->flags &= ~MAP_ATTRIB;
+    if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+    mem->card_start = addr & ~(s->cap.map_size-1);
+    
+    for (; len > 0; sys = s->cis_virt) {
+	s->ss_entry(s->sock, SS_SetMemMap, mem);
+	for ( ; len > 0; len--, ((u_char *)ptr)++, sys += inc) {
+	    if (sys == s->cis_virt+s->cap.map_size) break;
+	    bus_writeb(s->cap.bus, *(u_char *)ptr, sys);
+	}
+	mem->card_start += s->cap.map_size;
+    }
+}
+
+/*======================================================================
+
+    This is tricky... when we set up CIS memory, we try to validate
+    the memory window space allocations.
+    
+======================================================================*/
+
+/* Scratch pointer to the socket we use for validation */
+static socket_info_t *vs = NULL;
+
+/* Validation function for cards with a valid CIS */
+static int cis_readable(u_long base)
+{
+    cisinfo_t info1, info2;
+    int ret;
+    vs->cis_mem.sys_start = base;
+    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+    ret = validate_cis(vs->clients, &info1);
+    /* invalidate mapping and CIS cache */
+    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+    if ((ret != 0) || (info1.Chains == 0))
+	return 0;
+    vs->cis_mem.sys_start = base+vs->cap.map_size;
+    vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size,
+			       vs->cap.map_size);
+    ret = validate_cis(vs->clients, &info2);
+    bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0;
+    return ((ret == 0) && (info1.Chains == info2.Chains));
+}
+
+/* Validation function for simple memory cards */
+static int checksum(u_long base)
+{
+    int i, a, b, d;
+    vs->cis_mem.sys_start = base;
+    vs->cis_mem.sys_stop = base+vs->cap.map_size-1;
+    vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size);
+    vs->cis_mem.card_start = 0;
+    vs->cis_mem.flags = MAP_ACTIVE;
+    vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem);
+    /* Don't bother checking every word... */
+    a = 0; b = -1;
+    for (i = 0; i < vs->cap.map_size; i += 44) {
+	d = bus_readl(vs->cap.bus, vs->cis_virt+i);
+	a += d; b &= d;
+    }
+    bus_iounmap(vs->cap.bus, vs->cis_virt);
+    return (b == -1) ? -1 : (a>>1);
+}
+
+static int checksum_match(u_long base)
+{
+    int a = checksum(base), b = checksum(base+vs->cap.map_size);
+    return ((a == b) && (a >= 0));
+}
+
+int setup_cis_mem(socket_info_t *s)
+{
+    if (s->cis_mem.sys_start == 0) {
+	int low = !(s->cap.features & SS_CAP_PAGE_REGS);
+	vs = s;
+	validate_mem(cis_readable, checksum_match, low);
+	s->cis_mem.sys_start = 0;
+	vs = NULL;
+	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
+			    "card services", s->cap.map_size, low)) {
+	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
+	    return CS_OUT_OF_RESOURCE;
+	}
+	s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
+	s->cis_mem.flags |= MAP_ACTIVE;
+	s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
+				  s->cap.map_size);
+    }
+    return 0;
+}
+
+void release_cis_mem(socket_info_t *s)
+{
+    if (s->cis_mem.sys_start != 0) {
+	s->cis_mem.flags &= ~MAP_ACTIVE;
+	s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem);
+	release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
+	bus_iounmap(s->cap.bus, s->cis_virt);
+	s->cis_mem.sys_start = 0;
+    }
+}
+
+/*======================================================================
+
+    This is a wrapper around read_cis_mem, with the same interface,
+    but which caches information, for cards whose CIS may not be
+    readable all the time.
+    
+======================================================================*/
+
+static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
+			   u_int len, void *ptr)
+{
+    int i;
+    char *caddr;
+
+    if (s->fake_cis) {
+	if (s->fake_cis_len > addr+len)
+	    memcpy(ptr, s->fake_cis+addr, len);
+	else
+	    memset(ptr, 0xff, len);
+	return;
+    }
+    caddr = s->cis_cache;
+    for (i = 0; i < s->cis_used; i++) {
+	if ((s->cis_table[i].addr == addr) &&
+	    (s->cis_table[i].len == len) &&
+	    (s->cis_table[i].attr == attr)) break;
+	caddr += s->cis_table[i].len;
+    }
+    if (i < s->cis_used) {
+	memcpy(ptr, caddr, len);
+	return;
+    }
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS)
+	read_cb_mem(s, 0, attr, addr, len, ptr);
+    else
+#endif
+	read_cis_mem(s, attr, addr, len, ptr);
+    /* Copy data into the cache, if there is room */
+    if ((i < MAX_CIS_TABLE) &&
+	(caddr+len < s->cis_cache+MAX_CIS_DATA)) {
+	s->cis_table[i].addr = addr;
+	s->cis_table[i].len = len;
+	s->cis_table[i].attr = attr;
+	s->cis_used++;
+	memcpy(caddr, ptr, len);
+    }	    
+}
+
+/*======================================================================
+
+    This verifies if the CIS of a card matches what is in the CIS
+    cache.
+    
+======================================================================*/
+
+int verify_cis_cache(socket_info_t *s)
+{
+    char buf[256], *caddr;
+    int i;
+    
+    caddr = s->cis_cache;
+    for (i = 0; i < s->cis_used; i++) {
+#ifdef CONFIG_CARDBUS
+	if (s->state & SOCKET_CARDBUS)
+	    read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr,
+			s->cis_table[i].len, buf);
+	else
+#endif
+	    read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr,
+			 s->cis_table[i].len, buf);
+	if (memcmp(buf, caddr, s->cis_table[i].len) != 0)
+	    break;
+	caddr += s->cis_table[i].len;
+    }
+    return (i < s->cis_used);
+}
+
+/*======================================================================
+
+    For really bad cards, we provide a facility for uploading a
+    replacement CIS.
+    
+======================================================================*/
+
+int replace_cis(client_handle_t handle, cisdump_t *cis)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (s->fake_cis != NULL) {
+	kfree(s->fake_cis);
+	s->fake_cis = NULL;
+    }
+    if (cis->Length > CISTPL_MAX_CIS_SIZE)
+	return CS_BAD_SIZE;
+    s->fake_cis = kmalloc(cis->Length, GFP_KERNEL);
+    if (s->fake_cis == NULL)
+	return CS_OUT_OF_RESOURCE;
+    s->fake_cis_len = cis->Length;
+    memcpy(s->fake_cis, cis->Data, cis->Length);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    The high-level CIS tuple services
+    
+======================================================================*/
+
+typedef struct tuple_flags {
+    u_int		link_space:3;
+    u_int		has_link:1;
+    u_int		mfc_fn:3;
+    u_int		space:3;
+} tuple_flags;
+
+#define LINK_SPACE(f)	(((tuple_flags *)(&(f)))->link_space)
+#define HAS_LINK(f)	(((tuple_flags *)(&(f)))->has_link)
+#define MFC_FN(f)	(((tuple_flags *)(&(f)))->mfc_fn)
+#define SPACE(f)	(((tuple_flags *)(&(f)))->space)
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+
+int get_first_tuple(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    tuple->TupleLink = tuple->Flags = 0;
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS) {
+	u_int ptr;
+	pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr);
+	tuple->CISOffset = ptr & ~7;
+	SPACE(tuple->Flags) = (ptr & 7);
+    } else
+#endif
+    {
+	/* Assume presence of a LONGLINK_C to address 0 */
+	tuple->CISOffset = tuple->LinkOffset = 0;
+	SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
+    }
+    if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) &&
+	!(tuple->Attributes & TUPLE_RETURN_COMMON)) {
+	cisdata_t req = tuple->DesiredTuple;
+	tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
+	if (get_next_tuple(handle, tuple) == CS_SUCCESS) {
+	    tuple->DesiredTuple = CISTPL_LINKTARGET;
+	    if (get_next_tuple(handle, tuple) != CS_SUCCESS)
+		return CS_NO_MORE_ITEMS;
+	} else
+	    tuple->CISOffset = tuple->TupleLink = 0;
+	tuple->DesiredTuple = req;
+    }
+    return get_next_tuple(handle, tuple);
+}
+
+static int follow_link(socket_info_t *s, tuple_t *tuple)
+{
+    u_char link[5];
+    u_int ofs;
+
+    if (MFC_FN(tuple->Flags)) {
+	/* Get indirect link from the MFC tuple */
+	read_cis_cache(s, LINK_SPACE(tuple->Flags),
+		       tuple->LinkOffset, 5, link);
+	ofs = le32_to_cpu(*(u_int *)(link+1));
+	SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
+	/* Move to the next indirect link */
+	tuple->LinkOffset += 5;
+	MFC_FN(tuple->Flags)--;
+    } else if (HAS_LINK(tuple->Flags)) {
+	ofs = tuple->LinkOffset;
+	SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
+	HAS_LINK(tuple->Flags) = 0;
+    } else {
+	return -1;
+    }
+    if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) {
+	/* This is ugly, but a common CIS error is to code the long
+	   link offset incorrectly, so we check the right spot... */
+	read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+	if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
+	    (strncmp(link+2, "CIS", 3) == 0))
+	    return ofs;
+	/* Then, we try the wrong spot... */
+	ofs = ofs >> 1;
+    }
+    read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
+    if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) ||
+	(strncmp(link+2, "CIS", 3) != 0))
+	return -1;
+    return ofs;
+}
+
+int get_next_tuple(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    u_char link[2], tmp;
+    int ofs, i, attr;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+
+    link[1] = tuple->TupleLink;
+    ofs = tuple->CISOffset + tuple->TupleLink;
+    attr = SPACE(tuple->Flags);
+
+    for (i = 0; i < MAX_TUPLES; i++) {
+	if (link[1] == 0xff) {
+	    link[0] = CISTPL_END;
+	} else {
+	    read_cis_cache(s, attr, ofs, 2, link);
+	    if (link[0] == CISTPL_NULL) {
+		ofs++; continue;
+	    }
+	}
+	
+	/* End of chain?  Follow long link if possible */
+	if (link[0] == CISTPL_END) {
+	    if ((ofs = follow_link(s, tuple)) < 0)
+		return CS_NO_MORE_ITEMS;
+	    attr = SPACE(tuple->Flags);
+	    read_cis_cache(s, attr, ofs, 2, link);
+	}
+
+	/* Is this a link tuple?  Make a note of it */
+	if ((link[0] == CISTPL_LONGLINK_A) ||
+	    (link[0] == CISTPL_LONGLINK_C) ||
+	    (link[0] == CISTPL_LONGLINK_MFC) ||
+	    (link[0] == CISTPL_LINKTARGET) ||
+	    (link[0] == CISTPL_NO_LINK)) {
+	    switch (link[0]) {
+	    case CISTPL_LONGLINK_A:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = 1;
+		read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+		break;
+	    case CISTPL_LONGLINK_C:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = 0;
+		read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+		break;
+	    case CISTPL_LONGLINK_MFC:
+		tuple->LinkOffset = ofs + 3;
+		LINK_SPACE(tuple->Flags) = attr;
+		if (handle->Function == BIND_FN_ALL) {
+		    /* Follow all the MFC links */
+		    read_cis_cache(s, attr, ofs+2, 1, &tmp);
+		    MFC_FN(tuple->Flags) = tmp;
+		} else {
+		    /* Follow exactly one of the links */
+		    MFC_FN(tuple->Flags) = 1;
+		    tuple->LinkOffset += handle->Function * 5;
+		}
+		break;
+	    case CISTPL_NO_LINK:
+		HAS_LINK(tuple->Flags) = 0;
+		break;
+	    }
+	    if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
+		(tuple->DesiredTuple == RETURN_FIRST_TUPLE))
+		break;
+	} else
+	    if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
+		break;
+	
+	if (link[0] == tuple->DesiredTuple)
+	    break;
+	ofs += link[1] + 2;
+    }
+    if (i == MAX_TUPLES) {
+	DEBUG(1, "cs: overrun in get_next_tuple for socket %d\n",
+	      handle->Socket);
+	return CS_NO_MORE_ITEMS;
+    }
+    
+    tuple->TupleCode = link[0];
+    tuple->TupleLink = link[1];
+    tuple->CISOffset = ofs + 2;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int get_tuple_data(client_handle_t handle, tuple_t *tuple)
+{
+    socket_info_t *s;
+    u_int len;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+
+    s = SOCKET(handle);
+
+    if (tuple->TupleLink < tuple->TupleOffset)
+	return CS_NO_MORE_ITEMS;
+    len = tuple->TupleLink - tuple->TupleOffset;
+    tuple->TupleDataLen = tuple->TupleLink;
+    if (len == 0)
+	return CS_SUCCESS;
+    read_cis_cache(s, SPACE(tuple->Flags),
+		   tuple->CISOffset + tuple->TupleOffset,
+		   MIN(len, tuple->TupleDataMax), tuple->TupleData);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    Parsing routines for individual tuples
+    
+======================================================================*/
+
+static int parse_device(tuple_t *tuple, cistpl_device_t *device)
+{
+    int i;
+    u_char scale;
+    u_char *p, *q;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    device->ndev = 0;
+    for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
+	
+	if (*p == 0xff) break;
+	device->dev[i].type = (*p >> 4);
+	device->dev[i].wp = (*p & 0x08) ? 1 : 0;
+	switch (*p & 0x07) {
+	case 0: device->dev[i].speed = 0;   break;
+	case 1: device->dev[i].speed = 250; break;
+	case 2: device->dev[i].speed = 200; break;
+	case 3: device->dev[i].speed = 150; break;
+	case 4: device->dev[i].speed = 100; break;
+	case 7:
+	    if (++p == q) return CS_BAD_TUPLE;
+	    if (p == q)
+		return CS_BAD_TUPLE;
+	    device->dev[i].speed = SPEED_CVT(*p);
+	    while (*p & 0x80)
+		if (++p == q) return CS_BAD_TUPLE;
+	    break;
+	default:
+	    return CS_BAD_TUPLE;
+	}
+
+	if (++p == q) return CS_BAD_TUPLE;
+	if (*p == 0xff) break;
+	scale = *p & 7;
+	if (scale == 7) return CS_BAD_TUPLE;
+	device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
+	device->ndev++;
+	if (++p == q) break;
+    }
+    
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 5)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2;
+    csum->len = le16_to_cpu(*(u_short *)(p + 2));
+    csum->sum = *(p+4);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
+{
+    if (tuple->TupleDataLen < 4)
+	return CS_BAD_TUPLE;
+    link->addr = le32_to_cpu(*(u_int *)tuple->TupleData);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_longlink_mfc(tuple_t *tuple,
+			      cistpl_longlink_mfc_t *link)
+{
+    u_char *p;
+    int i;
+    
+    p = (u_char *)tuple->TupleData;
+    
+    link->nfn = *p; p++;
+    if (tuple->TupleDataLen <= link->nfn*5)
+	return CS_BAD_TUPLE;
+    for (i = 0; i < link->nfn; i++) {
+	link->fn[i].space = *p; p++;
+	link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4;
+    }
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_strings(u_char *p, u_char *q, int max,
+			 char *s, u_char *ofs, u_char *found)
+{
+    int i, j, ns;
+
+    if (p == q) return CS_BAD_TUPLE;
+    ns = 0; j = 0;
+    for (i = 0; i < max; i++) {
+	if (*p == 0xff) break;
+	ofs[i] = j;
+	ns++;
+	for (;;) {
+	    s[j++] = (*p == 0xff) ? '\0' : *p;
+	    if ((*p == '\0') || (*p == 0xff)) break;
+	    if (++p == q) return CS_BAD_TUPLE;
+	}
+	if ((*p == 0xff) || (++p == q)) break;
+    }
+    if (found) {
+	*found = ns;
+	return CS_SUCCESS;
+    } else {
+	return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE;
+    }
+}
+
+/*====================================================================*/
+
+static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
+{
+    u_char *p, *q;
+    
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    
+    vers_1->major = *p; p++;
+    vers_1->minor = *p; p++;
+    if (p >= q) return CS_BAD_TUPLE;
+
+    return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
+			 vers_1->str, vers_1->ofs, &vers_1->ns);
+}
+
+/*====================================================================*/
+
+static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
+{
+    u_char *p, *q;
+    
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    
+    return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
+			 altstr->str, altstr->ofs, &altstr->ns);
+}
+
+/*====================================================================*/
+
+static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
+{
+    u_char *p, *q;
+    int nid;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
+	if (p > q-2) break;
+	jedec->id[nid].mfr = p[0];
+	jedec->id[nid].info = p[1];
+	p += 2;
+    }
+    jedec->nid = nid;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
+{
+    u_short *p;
+    if (tuple->TupleDataLen < 4)
+	return CS_BAD_TUPLE;
+    p = (u_short *)tuple->TupleData;
+    m->manf = le16_to_cpu(p[0]);
+    m->card = le16_to_cpu(p[1]);
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 2)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    f->func = p[0];
+    f->sysinit = p[1];
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
+{
+    u_char *p;
+    int i;
+    if (tuple->TupleDataLen < 1)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    f->type = p[0];
+    for (i = 1; i < tuple->TupleDataLen; i++)
+	f->data[i-1] = p[i];
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_config(tuple_t *tuple, cistpl_config_t *config)
+{
+    int rasz, rmsz, i;
+    u_char *p;
+
+    p = (u_char *)tuple->TupleData;
+    rasz = *p & 0x03;
+    rmsz = (*p & 0x3c) >> 2;
+    if (tuple->TupleDataLen < rasz+rmsz+4)
+	return CS_BAD_TUPLE;
+    config->last_idx = *(++p);
+    p++;
+    config->base = 0;
+    for (i = 0; i <= rasz; i++)
+	config->base += p[i] << (8*i);
+    p += rasz+1;
+    for (i = 0; i < 4; i++)
+	config->rmask[i] = 0;
+    for (i = 0; i <= rmsz; i++)
+	config->rmask[i>>2] += p[i] << (8*(i%4));
+    config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
+    return CS_SUCCESS;
+}
+
+/*======================================================================
+
+    The following routines are all used to parse the nightmarish
+    config table entries.
+    
+======================================================================*/
+
+static u_char *parse_power(u_char *p, u_char *q,
+			   cistpl_power_t *pwr)
+{
+    int i;
+    u_int scale;
+
+    if (p == q) return NULL;
+    pwr->present = *p;
+    pwr->flags = 0;
+    p++;
+    for (i = 0; i < 7; i++)
+	if (pwr->present & (1<<i)) {
+	    if (p == q) return NULL;
+	    pwr->param[i] = POWER_CVT(*p);
+	    scale = POWER_SCALE(*p);
+	    while (*p & 0x80) {
+		if (++p == q) return NULL;
+		if ((*p & 0x7f) < 100)
+		    pwr->param[i] += (*p & 0x7f) * scale / 100;
+		else if (*p == 0x7d)
+		    pwr->flags |= CISTPL_POWER_HIGHZ_OK;
+		else if (*p == 0x7e)
+		    pwr->param[i] = 0;
+		else if (*p == 0x7f)
+		    pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
+		else
+		    return NULL;
+	    }
+	    p++;
+	}
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_timing(u_char *p, u_char *q,
+			    cistpl_timing_t *timing)
+{
+    u_char scale;
+
+    if (p == q) return NULL;
+    scale = *p;
+    if ((scale & 3) != 3) {
+	if (++p == q) return NULL;
+	timing->wait = SPEED_CVT(*p);
+	timing->waitscale = exponent[scale & 3];
+    } else
+	timing->wait = 0;
+    scale >>= 2;
+    if ((scale & 7) != 7) {
+	if (++p == q) return NULL;
+	timing->ready = SPEED_CVT(*p);
+	timing->rdyscale = exponent[scale & 7];
+    } else
+	timing->ready = 0;
+    scale >>= 3;
+    if (scale != 7) {
+	if (++p == q) return NULL;
+	timing->reserved = SPEED_CVT(*p);
+	timing->rsvscale = exponent[scale];
+    } else
+	timing->reserved = 0;
+    p++;
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
+{
+    int i, j, bsz, lsz;
+
+    if (p == q) return NULL;
+    io->flags = *p;
+
+    if (!(*p & 0x80)) {
+	io->nwin = 1;
+	io->win[0].base = 0;
+	io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
+	return p+1;
+    }
+    
+    if (++p == q) return NULL;
+    io->nwin = (*p & 0x0f) + 1;
+    bsz = (*p & 0x30) >> 4;
+    if (bsz == 3) bsz++;
+    lsz = (*p & 0xc0) >> 6;
+    if (lsz == 3) lsz++;
+    p++;
+    
+    for (i = 0; i < io->nwin; i++) {
+	io->win[i].base = 0;
+	io->win[i].len = 1;
+	for (j = 0; j < bsz; j++, p++) {
+	    if (p == q) return NULL;
+	    io->win[i].base += *p << (j*8);
+	}
+	for (j = 0; j < lsz; j++, p++) {
+	    if (p == q) return NULL;
+	    io->win[i].len += *p << (j*8);
+	}
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
+{
+    int i, j, asz, lsz, has_ha;
+    u_int len, ca, ha;
+
+    if (p == q) return NULL;
+
+    mem->nwin = (*p & 0x07) + 1;
+    lsz = (*p & 0x18) >> 3;
+    asz = (*p & 0x60) >> 5;
+    has_ha = (*p & 0x80);
+    if (++p == q) return NULL;
+    
+    for (i = 0; i < mem->nwin; i++) {
+	len = ca = ha = 0;
+	for (j = 0; j < lsz; j++, p++) {
+	    if (p == q) return NULL;
+	    len += *p << (j*8);
+	}
+	for (j = 0; j < asz; j++, p++) {
+	    if (p == q) return NULL;
+	    ca += *p << (j*8);
+	}
+	if (has_ha)
+	    for (j = 0; j < asz; j++, p++) {
+		if (p == q) return NULL;
+		ha += *p << (j*8);
+	    }
+	mem->win[i].len = len << 8;
+	mem->win[i].card_addr = ca << 8;
+	mem->win[i].host_addr = ha << 8;
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
+{
+    if (p == q) return NULL;
+    irq->IRQInfo1 = *p; p++;
+    if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
+	if (p+2 > q) return NULL;
+	irq->IRQInfo2 = (p[1]<<8) + p[0];
+	p += 2;
+    }
+    return p;
+}
+
+/*====================================================================*/
+
+static int parse_cftable_entry(tuple_t *tuple,
+			       cistpl_cftable_entry_t *entry)
+{
+    u_char *p, *q, features;
+
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    entry->index = *p & 0x3f;
+    entry->flags = 0;
+    if (*p & 0x40)
+	entry->flags |= CISTPL_CFTABLE_DEFAULT;
+    if (*p & 0x80) {
+	if (++p == q) return CS_BAD_TUPLE;
+	if (*p & 0x10)
+	    entry->flags |= CISTPL_CFTABLE_BVDS;
+	if (*p & 0x20)
+	    entry->flags |= CISTPL_CFTABLE_WP;
+	if (*p & 0x40)
+	    entry->flags |= CISTPL_CFTABLE_RDYBSY;
+	if (*p & 0x80)
+	    entry->flags |= CISTPL_CFTABLE_MWAIT;
+	entry->interface = *p & 0x0f;
+    } else
+	entry->interface = 0;
+
+    /* Process optional features */
+    if (++p == q) return CS_BAD_TUPLE;
+    features = *p; p++;
+
+    /* Power options */
+    if ((features & 3) > 0) {
+	p = parse_power(p, q, &entry->vcc);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vcc.present = 0;
+    if ((features & 3) > 1) {
+	p = parse_power(p, q, &entry->vpp1);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp1.present = 0;
+    if ((features & 3) > 2) {
+	p = parse_power(p, q, &entry->vpp2);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp2.present = 0;
+
+    /* Timing options */
+    if (features & 0x04) {
+	p = parse_timing(p, q, &entry->timing);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else {
+	entry->timing.wait = 0;
+	entry->timing.ready = 0;
+	entry->timing.reserved = 0;
+    }
+    
+    /* I/O window options */
+    if (features & 0x08) {
+	p = parse_io(p, q, &entry->io);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->io.nwin = 0;
+    
+    /* Interrupt options */
+    if (features & 0x10) {
+	p = parse_irq(p, q, &entry->irq);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->irq.IRQInfo1 = 0;
+
+    switch (features & 0x60) {
+    case 0x00:
+	entry->mem.nwin = 0;
+	break;
+    case 0x20:
+	entry->mem.nwin = 1;
+	entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+	entry->mem.win[0].card_addr = 0;
+	entry->mem.win[0].host_addr = 0;
+	p += 2;
+	if (p > q) return CS_BAD_TUPLE;
+	break;
+    case 0x40:
+	entry->mem.nwin = 1;
+	entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8;
+	entry->mem.win[0].card_addr =
+	    le16_to_cpu(*(u_short *)(p+2)) << 8;
+	entry->mem.win[0].host_addr = 0;
+	p += 4;
+	if (p > q) return CS_BAD_TUPLE;
+	break;
+    case 0x60:
+	p = parse_mem(p, q, &entry->mem);
+	if (p == NULL) return CS_BAD_TUPLE;
+	break;
+    }
+
+    /* Misc features */
+    if (features & 0x80) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->flags |= (*p << 8);
+	while (*p & 0x80)
+	    if (++p == q) return CS_BAD_TUPLE;
+	p++;
+    }
+
+    entry->subtuples = q-p;
+    
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar)
+{
+    u_char *p;
+    if (tuple->TupleDataLen < 6)
+	return CS_BAD_TUPLE;
+    p = (u_char *)tuple->TupleData;
+    bar->attr = *p;
+    p += 2;
+    bar->size = le32_to_cpu(*(u_int *)p);
+    return CS_SUCCESS;
+}
+
+static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config)
+{
+    u_char *p;
+    
+    p = (u_char *)tuple->TupleData;
+    if ((*p != 3) || (tuple->TupleDataLen < 6))
+	return CS_BAD_TUPLE;
+    config->last_idx = *(++p);
+    p++;
+    config->base = le32_to_cpu(*(u_int *)p);
+    config->subtuples = tuple->TupleDataLen - 6;
+    return CS_SUCCESS;
+}
+
+static int parse_cftable_entry_cb(tuple_t *tuple,
+				  cistpl_cftable_entry_cb_t *entry)
+{
+    u_char *p, *q, features;
+
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    entry->index = *p & 0x3f;
+    entry->flags = 0;
+    if (*p & 0x40)
+	entry->flags |= CISTPL_CFTABLE_DEFAULT;
+
+    /* Process optional features */
+    if (++p == q) return CS_BAD_TUPLE;
+    features = *p; p++;
+
+    /* Power options */
+    if ((features & 3) > 0) {
+	p = parse_power(p, q, &entry->vcc);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vcc.present = 0;
+    if ((features & 3) > 1) {
+	p = parse_power(p, q, &entry->vpp1);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp1.present = 0;
+    if ((features & 3) > 2) {
+	p = parse_power(p, q, &entry->vpp2);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->vpp2.present = 0;
+
+    /* I/O window options */
+    if (features & 0x08) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->io = *p; p++;
+    } else
+	entry->io = 0;
+    
+    /* Interrupt options */
+    if (features & 0x10) {
+	p = parse_irq(p, q, &entry->irq);
+	if (p == NULL) return CS_BAD_TUPLE;
+    } else
+	entry->irq.IRQInfo1 = 0;
+
+    if (features & 0x20) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->mem = *p; p++;
+    } else
+	entry->mem = 0;
+
+    /* Misc features */
+    if (features & 0x80) {
+	if (p == q) return CS_BAD_TUPLE;
+	entry->flags |= (*p << 8);
+	if (*p & 0x80) {
+	    if (++p == q) return CS_BAD_TUPLE;
+	    entry->flags |= (*p << 16);
+	}
+	while (*p & 0x80)
+	    if (++p == q) return CS_BAD_TUPLE;
+	p++;
+    }
+
+    entry->subtuples = q-p;
+    
+    return CS_SUCCESS;
+}
+
+#endif
+
+/*====================================================================*/
+
+static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
+{
+    u_char *p, *q;
+    int n;
+
+    p = (u_char *)tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
+	if (p > q-6) break;
+	geo->geo[n].buswidth = p[0];
+	geo->geo[n].erase_block = 1 << (p[1]-1);
+	geo->geo[n].read_block  = 1 << (p[2]-1);
+	geo->geo[n].write_block = 1 << (p[3]-1);
+	geo->geo[n].partition   = 1 << (p[4]-1);
+	geo->geo[n].interleave  = 1 << (p[5]-1);
+	p += 6;
+    }
+    geo->ngeo = n;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
+{
+    u_char *p, *q;
+
+    if (tuple->TupleDataLen < 10)
+	return CS_BAD_TUPLE;
+    
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+
+    v2->vers = p[0];
+    v2->comply = p[1];
+    v2->dindex = le16_to_cpu(*(u_short *)(p+2));
+    v2->vspec8 = p[6];
+    v2->vspec9 = p[7];
+    v2->nhdr = p[8];
+    p += 9;
+    return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
+}
+
+/*====================================================================*/
+
+static int parse_org(tuple_t *tuple, cistpl_org_t *org)
+{
+    u_char *p, *q;
+    int i;
+    
+    p = tuple->TupleData;
+    q = p + tuple->TupleDataLen;
+    if (p == q) return CS_BAD_TUPLE;
+    org->data_org = *p;
+    if (++p == q) return CS_BAD_TUPLE;
+    for (i = 0; i < 30; i++) {
+	org->desc[i] = *p;
+	if (*p == '\0') break;
+	if (++p == q) return CS_BAD_TUPLE;
+    }
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+    int ret = CS_SUCCESS;
+    
+    if (tuple->TupleDataLen > tuple->TupleDataMax)
+	return CS_BAD_TUPLE;
+    switch (tuple->TupleCode) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+	ret = parse_device(tuple, &parse->device);
+	break;
+#ifdef CONFIG_CARDBUS
+    case CISTPL_BAR:
+	ret = parse_bar(tuple, &parse->bar);
+	break;
+    case CISTPL_CONFIG_CB:
+	ret = parse_config_cb(tuple, &parse->config);
+	break;
+    case CISTPL_CFTABLE_ENTRY_CB:
+	ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb);
+	break;
+#endif
+    case CISTPL_CHECKSUM:
+	ret = parse_checksum(tuple, &parse->checksum);
+	break;
+    case CISTPL_LONGLINK_A:
+    case CISTPL_LONGLINK_C:
+	ret = parse_longlink(tuple, &parse->longlink);
+	break;
+    case CISTPL_LONGLINK_MFC:
+	ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
+	break;
+    case CISTPL_VERS_1:
+	ret = parse_vers_1(tuple, &parse->version_1);
+	break;
+    case CISTPL_ALTSTR:
+	ret = parse_altstr(tuple, &parse->altstr);
+	break;
+    case CISTPL_JEDEC_A:
+    case CISTPL_JEDEC_C:
+	ret = parse_jedec(tuple, &parse->jedec);
+	break;
+    case CISTPL_MANFID:
+	ret = parse_manfid(tuple, &parse->manfid);
+	break;
+    case CISTPL_FUNCID:
+	ret = parse_funcid(tuple, &parse->funcid);
+	break;
+    case CISTPL_FUNCE:
+	ret = parse_funce(tuple, &parse->funce);
+	break;
+    case CISTPL_CONFIG:
+	ret = parse_config(tuple, &parse->config);
+	break;
+    case CISTPL_CFTABLE_ENTRY:
+	ret = parse_cftable_entry(tuple, &parse->cftable_entry);
+	break;
+    case CISTPL_DEVICE_GEO:
+    case CISTPL_DEVICE_GEO_A:
+	ret = parse_device_geo(tuple, &parse->device_geo);
+	break;
+    case CISTPL_VERS_2:
+	ret = parse_vers_2(tuple, &parse->vers_2);
+	break;
+    case CISTPL_ORG:
+	ret = parse_org(tuple, &parse->org);
+	break;
+    case CISTPL_NO_LINK:
+    case CISTPL_LINKTARGET:
+	ret = CS_SUCCESS;
+	break;
+    default:
+	ret = CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+    return ret;
+}
+
+/*======================================================================
+
+    This is used internally by Card Services to look up CIS stuff.
+    
+======================================================================*/
+
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse)
+{
+    tuple_t tuple;
+    cisdata_t buf[255];
+    int ret;
+    
+    tuple.DesiredTuple = code;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    ret = CardServices(GetFirstTuple, handle, &tuple, NULL);
+    if (ret != CS_SUCCESS) return ret;
+    tuple.TupleData = buf;
+    tuple.TupleOffset = 0;
+    tuple.TupleDataMax = sizeof(buf);
+    ret = CardServices(GetTupleData, handle, &tuple, NULL);
+    if (ret != CS_SUCCESS) return ret;
+    ret = CardServices(ParseTuple, handle, &tuple, parse);
+    return ret;
+}
+
+/*======================================================================
+
+    This tries to determine if a card has a sensible CIS.  It returns
+    the number of tuples in the CIS, or 0 if the CIS looks bad.  The
+    checks include making sure several critical tuples are present and
+    valid; seeing if the total number of tuples is reasonable; and
+    looking for tuples that use reserved codes.
+    
+======================================================================*/
+
+int validate_cis(client_handle_t handle, cisinfo_t *info)
+{
+    tuple_t tuple;
+    cisparse_t p;
+    int ret, reserved, errors;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    
+    info->Chains = reserved = errors = 0;
+    tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    ret = get_first_tuple(handle, &tuple);
+    if (ret != CS_SUCCESS)
+	return CS_SUCCESS;
+
+    /* First tuple should be DEVICE */
+    if (tuple.TupleCode != CISTPL_DEVICE)
+	errors++;
+    /* All cards should have a MANFID tuple */
+    if (read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS)
+	errors++;
+    /* All cards should have either a VERS_1 or a VERS_2 tuple.  But
+       at worst, we'll accept a CFTABLE_ENTRY that parses. */
+    if ((read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) &&
+	(read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS) &&
+	(read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) &&
+	(read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS))
+	errors++;
+    if (errors > 1)
+	return CS_SUCCESS;
+    
+    for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) {
+	ret = get_next_tuple(handle, &tuple);
+	if (ret != CS_SUCCESS) break;
+	if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) ||
+	    ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) ||
+	    ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff)))
+	    reserved++;
+    }
+    if ((info->Chains == MAX_TUPLES) || (reserved > 5))
+	info->Chains = 0;
+    
+    return CS_SUCCESS;
+}
+
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cs.c linux/drivers/pcmcia/cs.c
--- v2.3.16/linux/drivers/pcmcia/cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/cs.c	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,2256 @@
+/*======================================================================
+
+    PCMCIA Card Services -- core services
+
+    cs.c 1.225 1999/09/07 15:19:32
+    
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/bus_ops.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+#endif
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"cs.c 1.225 1999/09/07 15:19:32 (David Hinds)";
+#endif
+
+static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
+
+static const char *options = "options: "
+#ifdef CONFIG_PCI
+" [pci]"
+#endif
+#ifdef CONFIG_CARDBUS
+" [cardbus]"
+#endif
+#ifdef CONFIG_APM
+" [apm]"
+#endif
+#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_APM)
+" none"
+#endif
+;
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int setup_delay		= HZ/20;	/* ticks */
+static int resume_delay		= HZ/5;		/* ticks */
+static int shutdown_delay	= HZ/40;	/* ticks */
+static int vcc_settle		= HZ*3/10;	/* ticks */
+static int reset_time		= 10;		/* usecs */
+static int unreset_delay	= HZ/10;	/* ticks */
+static int unreset_check	= HZ/10;	/* ticks */
+static int unreset_limit	= 30;		/* unreset_check's */
+
+/* Access speed for attribute memory windows */
+static int cis_speed		= 300;	/* ns */
+
+/* Access speed for IO windows */
+static int io_speed		= 0;	/* ns */
+
+/* Optional features */
+#ifdef CONFIG_APM
+static int do_apm		= 1;
+MODULE_PARM(do_apm, "i");
+#endif
+
+MODULE_PARM(setup_delay, "i");
+MODULE_PARM(resume_delay, "i");
+MODULE_PARM(shutdown_delay, "i");
+MODULE_PARM(vcc_settle, "i");
+MODULE_PARM(reset_time, "i");
+MODULE_PARM(unreset_delay, "i");
+MODULE_PARM(unreset_check, "i");
+MODULE_PARM(unreset_limit, "i");
+MODULE_PARM(cis_speed, "i");
+MODULE_PARM(io_speed, "i");
+
+/*====================================================================*/
+
+static socket_state_t dead_socket = {
+    0, SS_DETECT, 0, 0, 0
+};
+
+/* Table of sockets */
+socket_t sockets = 0;
+socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_pccard = NULL;
+#endif
+
+/*====================================================================*/
+
+/* String tables for error messages */
+
+typedef struct lookup_t {
+    int key;
+    char *msg;
+} lookup_t;
+
+static const lookup_t error_table[] = {
+    { CS_SUCCESS,		"Operation succeeded" },
+    { CS_BAD_ADAPTER,		"Bad adapter" },
+    { CS_BAD_ATTRIBUTE, 	"Bad attribute", },
+    { CS_BAD_BASE,		"Bad base address" },
+    { CS_BAD_EDC,		"Bad EDC" },
+    { CS_BAD_IRQ,		"Bad IRQ" },
+    { CS_BAD_OFFSET,		"Bad offset" },
+    { CS_BAD_PAGE,		"Bad page number" },
+    { CS_READ_FAILURE,		"Read failure" },
+    { CS_BAD_SIZE,		"Bad size" },
+    { CS_BAD_SOCKET,		"Bad socket" },
+    { CS_BAD_TYPE,		"Bad type" },
+    { CS_BAD_VCC,		"Bad Vcc" },
+    { CS_BAD_VPP,		"Bad Vpp" },
+    { CS_BAD_WINDOW,		"Bad window" },
+    { CS_WRITE_FAILURE,		"Write failure" },
+    { CS_NO_CARD,		"No card present" },
+    { CS_UNSUPPORTED_FUNCTION,	"Usupported function" },
+    { CS_UNSUPPORTED_MODE,	"Unsupported mode" },
+    { CS_BAD_SPEED,		"Bad speed" },
+    { CS_BUSY,			"Resource busy" },
+    { CS_GENERAL_FAILURE,	"General failure" },
+    { CS_WRITE_PROTECTED,	"Write protected" },
+    { CS_BAD_ARG_LENGTH,	"Bad argument length" },
+    { CS_BAD_ARGS,		"Bad arguments" },
+    { CS_CONFIGURATION_LOCKED,	"Configuration locked" },
+    { CS_IN_USE,		"Resource in use" },
+    { CS_NO_MORE_ITEMS,		"No more items" },
+    { CS_OUT_OF_RESOURCE,	"Out of resource" },
+    { CS_BAD_HANDLE,		"Bad handle" },
+    { CS_BAD_TUPLE,		"Bad CIS tuple" }
+};
+#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t))
+
+static const lookup_t service_table[] = {
+    { AccessConfigurationRegister,	"AccessConfigurationRegister" },
+    { AddSocketServices,		"AddSocketServices" },
+    { AdjustResourceInfo,		"AdjustResourceInfo" },
+    { CheckEraseQueue,			"CheckEraseQueue" },
+    { CloseMemory,			"CloseMemory" },
+    { DeregisterClient,			"DeregisterClient" },
+    { DeregisterEraseQueue,		"DeregisterEraseQueue" },
+    { GetCardServicesInfo,		"GetCardServicesInfo" },
+    { GetClientInfo,			"GetClientInfo" },
+    { GetConfigurationInfo,		"GetConfigurationInfo" },
+    { GetEventMask,			"GetEventMask" },
+    { GetFirstClient,			"GetFirstClient" },
+    { GetFirstRegion,			"GetFirstRegion" },
+    { GetFirstTuple,			"GetFirstTuple" },
+    { GetNextClient,			"GetNextClient" },
+    { GetNextRegion,			"GetNextRegion" },
+    { GetNextTuple,			"GetNextTuple" },
+    { GetStatus,			"GetStatus" },
+    { GetTupleData,			"GetTupleData" },
+    { MapMemPage,			"MapMemPage" },
+    { ModifyConfiguration,		"ModifyConfiguration" },
+    { ModifyWindow,			"ModifyWindow" },
+    { OpenMemory,			"OpenMemory" },
+    { ParseTuple,			"ParseTuple" },
+    { ReadMemory,			"ReadMemory" },
+    { RegisterClient,			"RegisterClient" },
+    { RegisterEraseQueue,		"RegisterEraseQueue" },
+    { RegisterMTD,			"RegisterMTD" },
+    { ReleaseConfiguration,		"ReleaseConfiguration" },
+    { ReleaseIO,			"ReleaseIO" },
+    { ReleaseIRQ,			"ReleaseIRQ" },
+    { ReleaseWindow,			"ReleaseWindow" },
+    { RequestConfiguration,		"RequestConfiguration" },
+    { RequestIO,			"RequestIO" },
+    { RequestIRQ,			"RequestIRQ" },
+    { RequestSocketMask,		"RequestSocketMask" },
+    { RequestWindow,			"RequestWindow" },
+    { ResetCard,			"ResetCard" },
+    { SetEventMask,			"SetEventMask" },
+    { ValidateCIS,			"ValidateCIS" },
+    { WriteMemory,			"WriteMemory" },
+    { BindDevice,			"BindDevice" },
+    { BindMTD,				"BindMTD" },
+    { ReportError,			"ReportError" },
+    { SuspendCard,			"SuspendCard" },
+    { ResumeCard,			"ResumeCard" },
+    { EjectCard,			"EjectCard" },
+    { InsertCard,			"InsertCard" },
+    { ReplaceCIS,			"ReplaceCIS" }
+};
+#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t))
+
+/*======================================================================
+
+    Reset a socket to the default state
+    
+======================================================================*/
+
+static void init_socket(socket_info_t *s)
+{
+    int i;
+    pccard_io_map io = { 0, 0, 0, 0, 1 };
+    pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
+
+    mem.sys_stop = s->cap.map_size;
+    s->socket = dead_socket;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    for (i = 0; i < 2; i++) {
+	io.map = i;
+	s->ss_entry(s->sock, SS_SetIOMap, &io);
+    }
+    for (i = 0; i < 5; i++) {
+	mem.map = i;
+	s->ss_entry(s->sock, SS_SetMemMap, &mem);
+    }
+}
+
+/*====================================================================*/
+
+#if defined(CONFIG_PROC_FS) && defined(PCMCIA_DEBUG)
+int proc_read_clients(char *buf, char **start, off_t pos,
+		      int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    client_handle_t c;
+    char *p = buf;
+
+    for (c = s->clients; c; c = c->next)
+	p += sprintf(p, "fn %x: '%s' [attr 0x%04x] [state 0x%04x]\n",
+		     c->Function, c->dev_info, c->Attributes, c->state);
+    return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+    Low-level PC Card interface drivers need to register with Card
+    Services using these calls.
+    
+======================================================================*/
+
+static void setup_socket(u_long i);
+static void shutdown_socket(u_long i);
+static void reset_socket(u_long i);
+static void unreset_socket(u_long i);
+static void parse_events(void *info, u_int events);
+
+int register_ss_entry(int nsock, ss_entry_t ss_entry)
+{
+    int i, ns;
+    socket_info_t *s;
+
+    DEBUG(0, "cs: register_ss_entry(%d, 0x%p)\n", nsock, ss_entry);
+
+    for (ns = 0; ns < nsock; ns++) {
+	s = kmalloc(sizeof(struct socket_info_t), GFP_KERNEL);
+	memset(s, 0, sizeof(socket_info_t));
+    
+	s->ss_entry = ss_entry;
+	s->sock = ns;
+	s->setup.data = sockets;
+	s->setup.function = &setup_socket;
+	s->shutdown.data = sockets;
+	s->shutdown.function = &shutdown_socket;
+	/* base address = 0, map = 0 */
+	s->cis_mem.flags = 0;
+	s->cis_mem.speed = cis_speed;
+	s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
+	
+	for (i = 0; i < sockets; i++)
+	    if (socket_table[i] == NULL) break;
+	socket_table[i] = s;
+	if (i == sockets) sockets++;
+
+	init_socket(s);
+	ss_entry(ns, SS_InquireSocket, &s->cap);
+#ifdef CONFIG_PROC_FS
+	if (proc_pccard) {
+	    char name[3];
+#ifdef PCMCIA_DEBUG
+	    struct proc_dir_entry *ent;
+#endif
+	    sprintf(name, "%02d", i);
+	    s->proc = create_proc_entry(name, S_IFDIR, proc_pccard);
+#ifdef PCMCIA_DEBUG
+	    ent = create_proc_entry("clients", 0, s->proc);
+	    ent->read_proc = proc_read_clients;
+	    ent->data = s;
+#endif
+	    ss_entry(ns, SS_ProcSetup, s->proc);
+	}
+#endif
+    }
+    
+    return 0;
+} /* register_ss_entry */
+
+/*====================================================================*/
+
+void unregister_ss_entry(ss_entry_t ss_entry)
+{
+    int i, j;
+    socket_info_t *s = NULL;
+    client_t *client;
+
+    for (;;) {
+	for (i = 0; i < sockets; i++) {
+	    s = socket_table[i];
+	    if (s->ss_entry == ss_entry) break;
+	}
+	if (i == sockets) {
+	    break;
+	} else {
+#ifdef CONFIG_PROC_FS
+	    if (proc_pccard) {
+		char name[3];
+		sprintf(name, "%02d", i);
+#ifdef PCMCIA_DEBUG
+		remove_proc_entry("clients", s->proc);
+#endif
+		remove_proc_entry(name, proc_pccard);
+	    }
+#endif
+	    while (s->clients) {
+		client = s->clients;
+		s->clients = s->clients->next;
+		kfree(client);
+	    }
+	    init_socket(s);
+	    release_cis_mem(s);
+#ifdef CONFIG_CARDBUS
+	    cb_release_cis_mem(s);
+#endif
+	    s->ss_entry = NULL;
+	    kfree(s);
+	    socket_table[i] = NULL;
+	    for (j = i; j < sockets-1; j++)
+		socket_table[j] = socket_table[j+1];
+	    sockets--;
+	}
+    }
+    
+} /* unregister_ss_entry */
+
+/*======================================================================
+
+    Shutdown_Socket() and setup_socket() are scheduled using add_timer
+    calls by the main event handler when card insertion and removal
+    events are received.  Shutdown_Socket() unconfigures a socket and
+    turns off socket power.  Setup_socket() turns on socket power
+    and resets the socket, in two stages.
+
+======================================================================*/
+
+static void free_regions(memory_handle_t *list)
+{
+    memory_handle_t tmp;
+    while (*list != NULL) {
+	tmp = *list;
+	*list = tmp->info.next;
+	tmp->region_magic = 0;
+	kfree(tmp);
+    }
+}
+
+static int send_event(socket_info_t *s, event_t event, int priority);
+
+static void shutdown_socket(u_long i)
+{
+    socket_info_t *s = socket_table[i];
+    client_t **c;
+    
+    DEBUG(1, "cs: shutdown_socket(%ld)\n", i);
+
+    /* Blank out the socket state */
+    s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING;
+    init_socket(s);
+    s->irq.AssignedIRQ = s->irq.Config = 0;
+    s->functions = 0;
+    s->lock_count = 0;
+    s->cis_used = 0;
+    if (s->fake_cis) {
+	kfree(s->fake_cis);
+	s->fake_cis = NULL;
+    }
+#ifdef CONFIG_CARDBUS
+    cb_release_cis_mem(s);
+    cb_free(s);
+#endif
+    if (s->config) {
+	kfree(s->config);
+	s->config = NULL;
+    }
+    for (c = &s->clients; *c; ) {
+	if ((*c)->state & CLIENT_UNBOUND) {
+	    client_t *d = *c;
+	    *c = (*c)->next;
+	    kfree(d);
+	} else {
+	    c = &((*c)->next);
+	}
+    }
+    free_regions(&s->a_region);
+    free_regions(&s->c_region);
+} /* shutdown_socket */
+
+static void setup_socket(u_long i)
+{
+    int val;
+    socket_info_t *s = socket_table[i];
+
+    s->ss_entry(s->sock, SS_GetStatus, &val);
+    if (val & SS_DETECT) {
+	DEBUG(1, "cs: setup_socket(%ld): applying power\n", i);
+	s->state |= SOCKET_PRESENT;
+	s->socket.flags = 0;
+	if (val & SS_3VCARD)
+	    s->socket.Vcc = s->socket.Vpp = 33;
+	else if (!(val & SS_XVCARD))
+	    s->socket.Vcc = s->socket.Vpp = 50;
+	else {
+	    printk(KERN_NOTICE "cs: socket %ld: unsupported "
+		   "voltage key\n", i);
+	    s->socket.Vcc = 0;
+	}
+	if (val & SS_CARDBUS) {
+	    s->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+	    printk(KERN_NOTICE "cs: unsupported card type detected!\n");
+#endif
+	}
+	s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+	s->setup.function = &reset_socket;
+	s->setup.expires = jiffies + vcc_settle;
+	add_timer(&s->setup);
+    } else
+	DEBUG(0, "cs: setup_socket(%ld): no card!\n", i);
+} /* setup_socket */
+
+/*======================================================================
+
+    Reset_socket() and unreset_socket() handle hard resets.  Resets
+    have several causes: card insertion, a call to reset_socket, or
+    recovery from a suspend/resume cycle.  Unreset_socket() sends
+    a CS event that matches the cause of the reset.
+    
+======================================================================*/
+
+static void reset_socket(u_long i)
+{
+    socket_info_t *s = socket_table[i];
+
+    DEBUG(1, "cs: resetting socket %ld\n", i);
+    s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    udelay((long)reset_time);
+    s->socket.flags &= ~SS_RESET;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    s->unreset_timeout = 0;
+    s->setup.expires = jiffies + unreset_delay;
+    s->setup.function = &unreset_socket;
+    add_timer(&s->setup);
+} /* reset_socket */
+
+#define EVENT_MASK \
+(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
+
+static void unreset_socket(u_long i)
+{
+    socket_info_t *s = socket_table[i];
+    int val;
+
+    s->ss_entry(s->sock, SS_GetStatus, &val);
+    if (val & SS_READY) {
+	DEBUG(1, "cs: reset done on socket %ld\n", i);
+	if (s->state & SOCKET_SUSPEND) {
+	    s->state &= ~EVENT_MASK;
+	    if (verify_cis_cache(s) != 0)
+		parse_events(s, SS_DETECT);
+	    else
+		send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+	} else if (s->state & SOCKET_SETUP_PENDING) {
+#ifdef CONFIG_CARDBUS
+	    if (s->state & SOCKET_CARDBUS)
+		cb_alloc(s);
+#endif
+	    send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+	    s->state &= ~SOCKET_SETUP_PENDING;
+	} else {
+	    send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+	    s->reset_handle->event_callback_args.info = NULL;
+	    EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
+		  CS_EVENT_PRI_LOW);
+	    s->state &= ~EVENT_MASK;
+	}
+    } else {
+	DEBUG(2, "cs: socket %ld not ready yet\n", i);
+	if (s->unreset_timeout > unreset_limit) {
+	    printk(KERN_NOTICE "cs: socket %ld timed out during"
+		   " reset\n", i);
+	    s->state &= ~EVENT_MASK;
+	} else {
+	    s->unreset_timeout++;
+	    s->setup.expires = jiffies + unreset_check;
+	    add_timer(&s->setup);
+	}
+    }
+} /* unreset_socket */
+
+/*======================================================================
+
+    The central event handler.  Send_event() sends an event to all
+    valid clients.  Parse_events() interprets the event bits from
+    a card status change report.  Do_shotdown() handles the high
+    priority stuff associated with a card removal.
+    
+======================================================================*/
+
+static int send_event(socket_info_t *s, event_t event, int priority)
+{
+    client_t *client = s->clients;
+    int ret;
+    DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n",
+	  s->sock, event, priority);
+    ret = 0;
+    for (; client; client = client->next) { 
+	if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
+	    continue;
+	if (client->EventMask & event) {
+	    ret = EVENT(client, event, priority);
+	    if (ret != 0)
+		return ret;
+	}
+    }
+    return ret;
+} /* send_event */
+
+static void do_shutdown(socket_info_t *s)
+{
+    client_t *client;
+    if (s->state & SOCKET_SHUTDOWN_PENDING)
+	return;
+    s->state |= SOCKET_SHUTDOWN_PENDING;
+    send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+    for (client = s->clients; client; client = client->next)
+	if (!(client->Attributes & INFO_MASTER_CLIENT))
+	    client->state |= CLIENT_STALE;
+    if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
+	DEBUG(0, "cs: flushing pending setup\n");
+	del_timer(&s->setup);
+	s->state &= ~EVENT_MASK;
+    }
+    s->shutdown.expires = jiffies + shutdown_delay;
+    add_timer(&s->shutdown);
+    s->state &= ~SOCKET_PRESENT;
+}
+
+static void parse_events(void *info, u_int events)
+{
+    socket_info_t *s = info;
+    if (events & SS_DETECT) {
+	int status;
+	u_long flags;
+	spin_lock_irqsave(&s->lock, flags);
+	s->ss_entry(s->sock, SS_GetStatus, &status);
+	if ((s->state & SOCKET_PRESENT) &&
+	    (!(s->state & SOCKET_SUSPEND) ||
+	     !(status & SS_DETECT)))
+	    do_shutdown(s);
+	if (status & SS_DETECT) {
+	    if (s->state & SOCKET_SETUP_PENDING) {
+		del_timer(&s->setup);
+		DEBUG(1, "cs: delaying pending setup\n");
+	    }
+	    s->state |= SOCKET_SETUP_PENDING;
+	    s->setup.function = &setup_socket;
+	    if (s->state & SOCKET_SUSPEND)
+		s->setup.expires = jiffies + resume_delay;
+	    else
+		s->setup.expires = jiffies + setup_delay;
+	    add_timer(&s->setup);
+	}
+	spin_unlock_irqrestore(&s->lock, flags);
+    }
+    if (events & SS_BATDEAD)
+	send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+    if (events & SS_BATWARN)
+	send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+    if (events & SS_READY) {
+	if (!(s->state & SOCKET_RESET_PENDING))
+	    send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+	else DEBUG(1, "cs: ready change during reset\n");
+    }
+} /* parse_events */
+
+/*======================================================================
+
+    Another event handler, for power management events.
+
+    This does not comply with the latest PC Card spec for handling
+    power management events.
+    
+======================================================================*/
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+    int i, stat;
+    socket_info_t *s;
+    static int down = 0;
+    
+    switch (event) {
+    case APM_SYS_SUSPEND:
+    case APM_USER_SUSPEND:
+	DEBUG(1, "cs: received suspend notification\n");
+	if (down) {
+	    printk(KERN_DEBUG "cs: received extra suspend event\n");
+	    break;
+	}
+	down = 1;
+	for (i = 0; i < sockets; i++) {
+	    s = socket_table[i];
+	    if ((s->state & SOCKET_PRESENT) &&
+		!(s->state & SOCKET_SUSPEND)){
+		send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+		s->ss_entry(s->sock, SS_SetSocket, &dead_socket);
+		s->state |= SOCKET_SUSPEND;
+	    }
+	}
+	break;
+    case APM_NORMAL_RESUME:
+    case APM_CRITICAL_RESUME:
+	DEBUG(1, "cs: received resume notification\n");
+	if (!down) {
+	    printk(KERN_DEBUG "cs: received bogus resume event\n");
+	    break;
+	}
+	down = 0;
+	for (i = 0; i < sockets; i++) {
+	    s = socket_table[i];
+	    /* Do this just to reinitialize the socket */
+	    init_socket(s);
+	    s->ss_entry(s->sock, SS_GetStatus, &stat);
+	    /* If there was or is a card here, we need to do something
+	       about it... but parse_events will sort it all out. */
+       	    if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
+		parse_events(s, SS_DETECT);
+	}
+	break;
+    }
+    return 0;
+} /* handle_apm_event */
+#endif
+
+/*======================================================================
+
+    Special stuff for managing IO windows, because they are scarce.
+    
+======================================================================*/
+
+static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base,
+			  ioaddr_t num, char *name)
+{
+    int i;
+    ioaddr_t try;
+    
+    for (i = 0; i < MAX_IO_WIN; i++) {
+	if (s->io[i].NumPorts == 0) {
+	    if (find_io_region(base, num, name) == 0) {
+		s->io[i].Attributes = attr;
+		s->io[i].BasePort = *base;
+		s->io[i].NumPorts = s->io[i].InUse = num;
+		break;
+	    } else
+		return 1;
+	} else if (s->io[i].Attributes != attr)
+	    continue;
+	/* Try to extend top of window */
+	try = s->io[i].BasePort + s->io[i].NumPorts;
+	if ((*base == 0) || (*base == try))
+	    if (find_io_region(&try, num, name) == 0) {
+		*base = try;
+		s->io[i].NumPorts += num;
+		s->io[i].InUse += num;
+		break;
+	    }
+	/* Try to extend bottom of window */
+	try = s->io[i].BasePort - num;
+	if ((*base == 0) || (*base == try))
+	    if (find_io_region(&try, num, name) == 0) {
+		s->io[i].BasePort = *base = try;
+		s->io[i].NumPorts += num;
+		s->io[i].InUse += num;
+		break;
+	    }
+    }
+    return (i == MAX_IO_WIN);
+} /* alloc_io_space */
+
+static void release_io_space(socket_info_t *s, ioaddr_t base,
+			     ioaddr_t num)
+{
+    int i;
+    release_region(base, num);
+    for (i = 0; i < MAX_IO_WIN; i++) {
+	if ((s->io[i].BasePort <= base) &&
+	    (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+	    s->io[i].InUse -= num;
+	    /* Free the window if no one else is using it */
+	    if (s->io[i].InUse == 0)
+		s->io[i].NumPorts = 0;
+	}
+    }
+}
+
+/*======================================================================
+
+    Access_configuration_register() reads and writes configuration
+    registers in attribute memory.  Memory window 0 is reserved for
+    this and the tuple reading services.
+    
+======================================================================*/
+
+static int access_configuration_register(client_handle_t handle,
+					 conf_reg_t *reg)
+{
+    socket_info_t *s;
+    config_t *c;
+    int addr;
+    u_char val;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (handle->Function == BIND_FN_ALL) {
+	if (reg->Function >= s->functions)
+	    return CS_BAD_ARGS;
+	c = &s->config[reg->Function];
+    } else
+	c = CONFIG(handle);
+    if (!(c->state & CONFIG_LOCKED))
+	return CS_CONFIGURATION_LOCKED;
+
+    addr = (c->ConfigBase + reg->Offset) >> 1;
+    
+    switch (reg->Action) {
+    case CS_READ:
+	read_cis_mem(s, 1, addr, 1, &val);
+	reg->Value = val;
+	break;
+    case CS_WRITE:
+	val = reg->Value;
+	write_cis_mem(s, 1, addr, 1, &val);
+	break;
+    default:
+	return CS_BAD_ARGS;
+	break;
+    }
+    return CS_SUCCESS;
+} /* access_configuration_register */
+
+/*======================================================================
+
+    Bind_device() associates a device driver with a particular socket.
+    It is normally called by Driver Services after it has identified
+    a newly inserted card.  An instance of that driver will then be
+    eligible to register as a client of this socket.
+    
+======================================================================*/
+
+static int bind_device(bind_req_t *req)
+{
+    client_t *client;
+    socket_info_t *s;
+
+    if (CHECK_SOCKET(req->Socket))
+	return CS_BAD_SOCKET;
+    s = SOCKET(req);
+
+    client = (client_t *)kmalloc(sizeof(client_t), GFP_KERNEL);
+    memset(client, '\0', sizeof(client_t));
+    client->client_magic = CLIENT_MAGIC;
+    strncpy(client->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+    client->Socket = req->Socket;
+    client->Function = req->Function;
+    client->state = CLIENT_UNBOUND;
+    client->erase_busy.next = &client->erase_busy;
+    client->erase_busy.prev = &client->erase_busy;
+    init_waitqueue_head(&client->mtd_req);
+    client->next = s->clients;
+    s->clients = client;
+    DEBUG(1, "cs: bind_device(): client 0x%p, sock %d, dev %s\n",
+	  client, client->Socket, client->dev_info);
+    return CS_SUCCESS;
+} /* bind_device */
+
+/*======================================================================
+
+    Bind_mtd() associates a device driver with a particular memory
+    region.  It is normally called by Driver Services after it has
+    identified a memory device type.  An instance of the corresponding
+    driver will then be able to register to control this region.
+    
+======================================================================*/
+
+static int bind_mtd(mtd_bind_t *req)
+{
+    socket_info_t *s;
+    memory_handle_t region;
+    
+    if (CHECK_SOCKET(req->Socket))
+	return CS_BAD_SOCKET;
+    s = SOCKET(req);
+    
+    if (req->Attributes & REGION_TYPE_AM)
+	region = s->a_region;
+    else
+	region = s->c_region;
+    
+    while (region) {
+	if (region->info.CardOffset == req->CardOffset) break;
+	region = region->info.next;
+    }
+    if (!region || (region->mtd != NULL))
+	return CS_BAD_OFFSET;
+    strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+    
+    DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",
+	  req->Attributes, req->CardOffset, (char *)req->dev_info);
+    return CS_SUCCESS;
+} /* bind_mtd */
+
+/*====================================================================*/
+
+static int deregister_client(client_handle_t handle)
+{
+    client_t **client;
+    socket_info_t *s;
+    memory_handle_t region;
+    u_long flags;
+    int i, sn;
+    
+    DEBUG(1, "cs: deregister_client(%p)\n", handle);
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    if (handle->state &
+	(CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+	return CS_IN_USE;
+    for (i = 0; i < MAX_WIN; i++)
+	if (handle->state & CLIENT_WIN_REQ(i))
+	    return CS_IN_USE;
+
+    /* Disconnect all MTD links */
+    s = SOCKET(handle);
+    if (handle->mtd_count) {
+	for (region = s->a_region; region; region = region->info.next)
+	    if (region->mtd == handle) region->mtd = NULL;
+	for (region = s->c_region; region; region = region->info.next)
+	    if (region->mtd == handle) region->mtd = NULL;
+    }
+    
+    sn = handle->Socket; s = socket_table[sn];
+
+    if ((handle->state & CLIENT_STALE) ||
+	(handle->Attributes & INFO_MASTER_CLIENT)) {
+	spin_lock_irqsave(&s->lock, flags);
+	client = &s->clients;
+	while ((*client) && ((*client) != handle))
+	    client = &(*client)->next;
+	if (*client == NULL)
+	    return CS_BAD_HANDLE;
+	*client = handle->next;
+	handle->client_magic = 0;
+	kfree(handle);
+	spin_unlock_irqrestore(&s->lock, flags);
+    } else {
+	handle->state = CLIENT_UNBOUND;
+	handle->mtd_count = 0;
+	handle->event_handler = NULL;
+    }
+
+    if (--s->real_clients == 0)
+	s->ss_entry(sn, SS_RegisterCallback, NULL);
+    
+    return CS_SUCCESS;
+} /* deregister_client */
+
+/*====================================================================*/
+
+static int get_configuration_info(client_handle_t handle,
+				  config_info_t *config)
+{
+    socket_info_t *s;
+    config_t *c;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+
+    if (handle->Function == BIND_FN_ALL) {
+	if (config->Function && (config->Function >= s->functions))
+	    return CS_BAD_ARGS;
+    } else
+	config->Function = handle->Function;
+    
+#ifdef CONFIG_CARDBUS
+    if (s->state & SOCKET_CARDBUS) {
+	u_char fn = config->Function;
+	memset(config, 0, sizeof(config_info_t));
+	config->Function = fn;
+	config->Vcc = s->socket.Vcc;
+	config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+	config->Option = s->cap.cardbus;
+	if (s->cb_config) {
+	    config->Attributes = CONF_VALID_CLIENT;
+	    config->IntType = INT_CARDBUS;
+	    config->AssignedIRQ = s->irq.AssignedIRQ;
+	    if (config->AssignedIRQ)
+		config->Attributes |= CONF_ENABLE_IRQ;
+	    config->BasePort1 = s->io[0].BasePort;
+	    config->NumPorts1 = s->io[0].NumPorts;
+	}
+	return CS_SUCCESS;
+    }
+#endif
+    
+    c = (s->config != NULL) ? &s->config[config->Function] : NULL;
+    
+    if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+	config->Attributes = 0;
+	config->Vcc = s->socket.Vcc;
+	config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+	return CS_SUCCESS;
+    }
+    
+    /* !!! This is a hack !!! */
+    memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+    config->Attributes |= CONF_VALID_CLIENT;
+    config->CardValues = c->CardValues;
+    config->IRQAttributes = c->irq.Attributes;
+    config->AssignedIRQ = s->irq.AssignedIRQ;
+    config->BasePort1 = c->io.BasePort1;
+    config->NumPorts1 = c->io.NumPorts1;
+    config->Attributes1 = c->io.Attributes1;
+    config->BasePort2 = c->io.BasePort2;
+    config->NumPorts2 = c->io.NumPorts2;
+    config->Attributes2 = c->io.Attributes2;
+    config->IOAddrLines = c->io.IOAddrLines;
+    
+    return CS_SUCCESS;
+} /* get_configuration_info */
+
+/*======================================================================
+
+    Return information about this version of Card Services.
+    
+======================================================================*/
+
+static int get_card_services_info(servinfo_t *info)
+{
+    info->Signature[0] = 'C';
+    info->Signature[1] = 'S';
+    info->Count = sockets;
+    info->Revision = CS_RELEASE_CODE;
+    info->CSLevel = 0x0210;
+    info->VendorString = (char *)release;
+    return CS_SUCCESS;
+} /* get_card_services_info */
+
+/*======================================================================
+
+    Note that get_first_client() *does* recognize the Socket field
+    in the request structure.
+    
+======================================================================*/
+
+static int get_first_client(client_handle_t *handle, client_req_t *req)
+{
+    socket_t s;
+    if (req->Attributes & CLIENT_THIS_SOCKET)
+	s = req->Socket;
+    else
+	s = 0;
+    if (CHECK_SOCKET(req->Socket))
+	return CS_BAD_SOCKET;
+    if (socket_table[s]->clients == NULL)
+	return CS_NO_MORE_ITEMS;
+    *handle = socket_table[s]->clients;
+    return CS_SUCCESS;
+} /* get_first_client */
+
+/*====================================================================*/
+
+static int get_next_client(client_handle_t *handle, client_req_t *req)
+{
+    socket_info_t *s;
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+	return CS_BAD_HANDLE;
+    if ((*handle)->next == NULL) {
+	if (req->Attributes & CLIENT_THIS_SOCKET)
+	    return CS_NO_MORE_ITEMS;
+	s = SOCKET(*handle);
+	if (s->clients == NULL)
+	    return CS_NO_MORE_ITEMS;
+	*handle = s->clients;
+    } else
+	*handle = (*handle)->next;
+    return CS_SUCCESS;
+} /* get_next_client */
+
+/*====================================================================*/
+
+static int get_window(window_handle_t *handle, int idx, win_req_t *req)
+{
+    socket_info_t *s;
+    window_t *win;
+    int w;
+
+    if (idx == 0)
+	s = SOCKET((client_handle_t)*handle);
+    else
+	s = (*handle)->sock;
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    for (w = idx; w < MAX_WIN; w++)
+	if (s->state & SOCKET_WIN_REQ(w)) break;
+    if (w == MAX_WIN)
+	return CS_NO_MORE_ITEMS;
+    win = &s->win[w];
+    req->Base = win->ctl.sys_start;
+    req->Size = win->ctl.sys_stop - win->ctl.sys_start + 1;
+    req->AccessSpeed = win->ctl.speed;
+    req->Attributes = 0;
+    if (win->ctl.flags & MAP_ATTRIB)
+	req->Attributes |= WIN_MEMORY_TYPE_AM;
+    if (win->ctl.flags & MAP_ACTIVE)
+	req->Attributes |= WIN_ENABLE;
+    if (win->ctl.flags & MAP_16BIT)
+	req->Attributes |= WIN_DATA_WIDTH;
+    if (win->ctl.flags & MAP_USE_WAIT)
+	req->Attributes |= WIN_USE_WAIT;
+    *handle = win;
+    return CS_SUCCESS;
+} /* get_window */
+
+static int get_first_window(client_handle_t *handle, win_req_t *req)
+{
+    if ((handle == NULL) || CHECK_HANDLE(*handle))
+	return CS_BAD_HANDLE;
+    return get_window((window_handle_t *)handle, 0, req);
+}
+
+static int get_next_window(window_handle_t *win, win_req_t *req)
+{
+    if ((win == NULL) || ((*win)->magic != WINDOW_MAGIC))
+	return CS_BAD_HANDLE;
+    return get_window(win, (*win)->index+1, req);
+}
+
+/*======================================================================
+
+    Get the current socket state bits.  We don't support the latched
+    SocketState yet: I haven't seen any point for it.
+    
+======================================================================*/
+
+static int get_status(client_handle_t handle, cs_status_t *status)
+{
+    socket_info_t *s;
+    config_t *c;
+    int val;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    s->ss_entry(s->sock, SS_GetStatus, &val);
+    status->CardState = status->SocketState = 0;
+    status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+    status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+    status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+    status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+    if (s->state & SOCKET_SUSPEND)
+	status->CardState |= CS_EVENT_PM_SUSPEND;
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    if (s->state & SOCKET_SETUP_PENDING)
+	status->CardState |= CS_EVENT_CARD_INSERTION;
+    
+    /* Get info from the PRR, if necessary */
+    if (handle->Function == BIND_FN_ALL) {
+	if (status->Function && (status->Function >= s->functions))
+	    return CS_BAD_ARGS;
+	c = (s->config != NULL) ? &s->config[status->Function] : NULL;
+    } else
+	c = CONFIG(handle);
+    if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+	(c->IntType & INT_MEMORY_AND_IO)) {
+	u_char reg;
+	if (c->Present & PRESENT_PIN_REPLACE) {
+	    read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
+	    status->CardState |=
+		(reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+	    status->CardState |=
+		(reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+	    status->CardState |=
+		(reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+	    status->CardState |=
+		(reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+	} else {
+	    /* No PRR?  Then assume we're always ready */
+	    status->CardState |= CS_EVENT_READY_CHANGE;
+	}
+	if (c->Present & PRESENT_EXT_STATUS) {
+	    read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
+	    status->CardState |=
+		(reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+	}
+	return CS_SUCCESS;
+    }
+    status->CardState |=
+	(val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+    status->CardState |=
+	(val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+    status->CardState |=
+	(val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+    status->CardState |=
+	(val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+    return CS_SUCCESS;
+} /* get_status */
+
+/*======================================================================
+
+    Change the card address of an already open memory window.
+    
+======================================================================*/
+
+static int get_mem_page(window_handle_t win, memreq_t *req)
+{
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+	return CS_BAD_HANDLE;
+    req->Page = 0;
+    req->CardOffset = win->ctl.card_start;
+    return CS_SUCCESS;
+} /* get_mem_page */
+
+static int map_mem_page(window_handle_t win, memreq_t *req)
+{
+    socket_info_t *s;
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+	return CS_BAD_HANDLE;
+    if (req->Page != 0)
+	return CS_BAD_PAGE;
+    s = win->sock;
+    win->ctl.card_start = req->CardOffset;
+    if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0)
+	return CS_BAD_OFFSET;
+    return CS_SUCCESS;
+} /* map_mem_page */
+
+/*======================================================================
+
+    Modify a locked socket configuration
+    
+======================================================================*/
+
+static int modify_configuration(client_handle_t handle,
+				modconf_t *mod)
+{
+    socket_info_t *s;
+    config_t *c;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle); c = CONFIG(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    if (!(c->state & CONFIG_LOCKED))
+	return CS_CONFIGURATION_LOCKED;
+    
+    if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+	if (mod->Attributes & CONF_ENABLE_IRQ) {
+	    c->Attributes |= CONF_ENABLE_IRQ;
+	    s->socket.io_irq = s->irq.AssignedIRQ;
+	} else {
+	    c->Attributes &= ~CONF_ENABLE_IRQ;
+	    s->socket.io_irq = 0;
+	}
+	s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    }
+
+    if (mod->Attributes & CONF_VCC_CHANGE_VALID)
+	return CS_BAD_VCC;
+
+    /* We only allow changing Vpp1 and Vpp2 to the same value */
+    if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
+	(mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+	if (mod->Vpp1 != mod->Vpp2)
+	    return CS_BAD_VPP;
+	c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
+	if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+	    return CS_BAD_VPP;
+    } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
+	       (mod->Attributes & CONF_VPP2_CHANGE_VALID))
+	return CS_BAD_VPP;
+
+    return CS_SUCCESS;
+} /* modify_configuration */
+
+/*======================================================================
+
+    Modify the attributes of a window returned by RequestWindow.
+
+======================================================================*/
+
+static int modify_window(window_handle_t win, modwin_t *req)
+{
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+	return CS_BAD_HANDLE;
+
+    win->ctl.flags &= ~(MAP_ATTRIB|MAP_ACTIVE);
+    if (req->Attributes & WIN_MEMORY_TYPE)
+	win->ctl.flags |= MAP_ATTRIB;
+    if (req->Attributes & WIN_ENABLE)
+	win->ctl.flags |= MAP_ACTIVE;
+    if (req->Attributes & WIN_DATA_WIDTH)
+	win->ctl.flags |= MAP_16BIT;
+    if (req->Attributes & WIN_USE_WAIT)
+	win->ctl.flags |= MAP_USE_WAIT;
+    win->ctl.speed = req->AccessSpeed;
+    win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
+    
+    return CS_SUCCESS;
+} /* modify_window */
+
+/*======================================================================
+
+    Register_client() uses the dev_info_t handle to match the
+    caller with a socket.  The driver must have already been bound
+    to a socket with bind_device() -- in fact, bind_device()
+    allocates the client structure that will be used.
+    
+======================================================================*/
+
+static int register_client(client_handle_t *handle, client_reg_t *req)
+{
+    client_t *client;
+    socket_info_t *s;
+    socket_t ns;
+    
+    /* Look for unbound client with matching dev_info */
+    client = NULL;
+    for (ns = 0; ns < sockets; ns++) {
+	client = socket_table[ns]->clients;
+	while (client != NULL) {
+	    if ((strcmp(client->dev_info, (char *)req->dev_info) == 0)
+		&& (client->state & CLIENT_UNBOUND)) break;
+	    client = client->next;
+	}
+	if (client != NULL) break;
+    }
+    if (client == NULL)
+	return CS_OUT_OF_RESOURCE;
+
+    s = socket_table[ns];
+    if (++s->real_clients == 1) {
+	ss_callback_t call;
+	int status;
+	call.handler = &parse_events;
+	call.info = s;
+	s->ss_entry(ns, SS_RegisterCallback, &call);
+	s->ss_entry(ns, SS_GetStatus, &status);
+	if ((status & SS_DETECT) &&
+	    !(s->state & SOCKET_SETUP_PENDING)) {
+	    s->state |= SOCKET_SETUP_PENDING;
+	    setup_socket(ns);
+	}
+    }
+
+    *handle = client;
+    client->state &= ~CLIENT_UNBOUND;
+    client->Socket = ns;
+    client->Attributes = req->Attributes;
+    client->EventMask = req->EventMask;
+    client->event_handler = req->event_handler;
+    client->event_callback_args = req->event_callback_args;
+    client->event_callback_args.client_handle = client;
+    client->event_callback_args.bus = s->cap.bus;
+
+    if (s->state & SOCKET_CARDBUS)
+	client->state |= CLIENT_CARDBUS;
+    
+    if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
+	(client->Function != BIND_FN_ALL)) {
+	cistpl_longlink_mfc_t mfc;
+	if (read_tuple(client, CISTPL_LONGLINK_MFC, &mfc)
+	    == CS_SUCCESS)
+	    s->functions = mfc.nfn;
+	else
+	    s->functions = 1;
+	s->config = kmalloc(sizeof(config_t) * s->functions,
+			    GFP_KERNEL);
+	memset(s->config, 0, sizeof(config_t) * s->functions);
+    }
+    
+    DEBUG(1, "cs: register_client(): client 0x%p, sock %d, dev %s\n",
+	  client, client->Socket, client->dev_info);
+    if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
+	EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
+    if ((socket_table[ns]->state & SOCKET_PRESENT) &&
+	!(socket_table[ns]->state & SOCKET_SETUP_PENDING)) {
+	if (client->EventMask & CS_EVENT_CARD_INSERTION)
+	    EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+	else
+	    client->PendingEvents |= CS_EVENT_CARD_INSERTION;
+    }
+    return CS_SUCCESS;
+} /* register_client */
+
+/*====================================================================*/
+
+static int release_configuration(client_handle_t handle,
+				 socket_t *Socket)
+{
+    pccard_io_map io;
+    socket_info_t *s;
+    int i;
+    
+    if (CHECK_HANDLE(handle) ||
+	!(handle->state & CLIENT_CONFIG_LOCKED))
+	return CS_BAD_HANDLE;
+    handle->state &= ~CLIENT_CONFIG_LOCKED;
+    s = SOCKET(handle);
+    
+#ifdef CONFIG_CARDBUS
+    if (handle->state & CLIENT_CARDBUS) {
+	cb_disable(s);
+	s->lock_count = 0;
+	return CS_SUCCESS;
+    }
+#endif
+    
+    if (!(handle->state & CLIENT_STALE)) {
+	config_t *c = CONFIG(handle);
+	if (--(s->lock_count) == 0) {
+	    s->socket.flags = SS_OUTPUT_ENA;
+	    s->socket.Vpp = 0;
+	    s->socket.io_irq = 0;
+	    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+	}
+	if (c->state & CONFIG_IO_REQ)
+	    for (i = 0; i < MAX_IO_WIN; i++) {
+		if (s->io[i].NumPorts == 0)
+		    continue;
+		s->io[i].Config--;
+		if (s->io[i].Config != 0)
+		    continue;
+		io.map = i;
+		s->ss_entry(s->sock, SS_GetIOMap, &io);
+		io.flags &= ~MAP_ACTIVE;
+		s->ss_entry(s->sock, SS_SetIOMap, &io);
+	    }
+	c->state &= ~CONFIG_LOCKED;
+    }
+    
+    return CS_SUCCESS;
+} /* release_configuration */
+
+/*======================================================================
+
+    Release_io() releases the I/O ranges allocated by a client.  This
+    may be invoked some time after a card ejection has already dumped
+    the actual socket configuration, so if the client is "stale", we
+    don't bother checking the port ranges against the current socket
+    values.
+    
+======================================================================*/
+
+static int release_io(client_handle_t handle, io_req_t *req)
+{
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+	return CS_BAD_HANDLE;
+    handle->state &= ~CLIENT_IO_REQ;
+    s = SOCKET(handle);
+    
+#ifdef CONFIG_CARDBUS
+    if (handle->state & CLIENT_CARDBUS) {
+	cb_release(s);
+	return CS_SUCCESS;
+    }
+#endif
+    
+    if (!(handle->state & CLIENT_STALE)) {
+	config_t *c = CONFIG(handle);
+	if (c->state & CONFIG_LOCKED)
+	    return CS_CONFIGURATION_LOCKED;
+	if ((c->io.BasePort1 != req->BasePort1) ||
+	    (c->io.NumPorts1 != req->NumPorts1) ||
+	    (c->io.BasePort2 != req->BasePort2) ||
+	    (c->io.NumPorts2 != req->NumPorts2))
+	    return CS_BAD_ARGS;
+	c->state &= ~CONFIG_IO_REQ;
+    }
+
+    release_io_space(s, req->BasePort1, req->NumPorts1);
+    if (req->NumPorts2)
+	release_io_space(s, req->BasePort2, req->NumPorts2);
+    
+    return CS_SUCCESS;
+} /* release_io */
+
+/*====================================================================*/
+
+static int cs_release_irq(client_handle_t handle, irq_req_t *req)
+{
+    socket_info_t *s;
+    if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
+	return CS_BAD_HANDLE;
+    handle->state &= ~CLIENT_IRQ_REQ;
+    s = SOCKET(handle);
+    
+    if (!(handle->state & CLIENT_STALE)) {
+	config_t *c = CONFIG(handle);
+	if (c->state & CONFIG_LOCKED)
+	    return CS_CONFIGURATION_LOCKED;
+	if (c->irq.Attributes != req->Attributes)
+	    return CS_BAD_ATTRIBUTE;
+	if (s->irq.AssignedIRQ != req->AssignedIRQ)
+	    return CS_BAD_IRQ;
+	if (--s->irq.Config == 0) {
+	    c->state &= ~CONFIG_IRQ_REQ;
+	    s->irq.AssignedIRQ = 0;
+	}
+    }
+    
+    if (req->Attributes & IRQ_HANDLE_PRESENT) {
+	bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance);
+    }
+
+#ifdef CONFIG_ISA
+    if (req->AssignedIRQ != s->cap.pci_irq)
+	undo_irq(req->Attributes, req->AssignedIRQ);
+#endif
+    
+    return CS_SUCCESS;
+} /* cs_release_irq */
+
+/*====================================================================*/
+
+static int release_window(window_handle_t win)
+{
+    socket_info_t *s;
+    
+    if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+	return CS_BAD_HANDLE;
+    s = win->sock;
+    if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+	return CS_BAD_HANDLE;
+
+    /* Shut down memory window */
+    win->ctl.flags &= ~MAP_ACTIVE;
+    s->ss_entry(s->sock, SS_SetMemMap, &win->ctl);
+    s->state &= ~SOCKET_WIN_REQ(win->index);
+
+    /* Release system memory */
+    release_mem_region(win->base, win->size);
+    win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+
+    win->magic = 0;
+    
+    return CS_SUCCESS;
+} /* release_window */
+
+/*====================================================================*/
+
+static int request_configuration(client_handle_t handle,
+				 config_req_t *req)
+{
+    int i;
+    u_int base;
+    socket_info_t *s;
+    config_t *c;
+    pccard_io_map iomap;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    
+#ifdef CONFIG_CARDBUS
+    if (handle->state & CLIENT_CARDBUS) {
+	if (!(req->IntType & INT_CARDBUS))
+	    return CS_UNSUPPORTED_MODE;
+	if (s->lock_count != 0)
+	    return CS_CONFIGURATION_LOCKED;
+	cb_enable(s);
+	handle->state |= CLIENT_CONFIG_LOCKED;
+	s->lock_count++;
+	return CS_SUCCESS;
+    }
+#endif
+    
+    if (req->IntType & INT_CARDBUS)
+	return CS_UNSUPPORTED_MODE;
+    c = CONFIG(handle);
+    if (c->state & CONFIG_LOCKED)
+	return CS_CONFIGURATION_LOCKED;
+
+    /* Do power control.  We don't allow changes in Vcc. */
+    if (s->socket.Vcc != req->Vcc)
+	return CS_BAD_VCC;
+    if (req->Vpp1 != req->Vpp2)
+	return CS_BAD_VPP;
+    s->socket.Vpp = req->Vpp1;
+    if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
+	return CS_BAD_VPP;
+    
+    c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+    
+    /* Pick memory or I/O card, DMA mode, interrupt */
+    c->IntType = req->IntType;
+    c->Attributes = req->Attributes;
+    if (req->IntType & INT_MEMORY_AND_IO)
+	s->socket.flags |= SS_IOCARD;
+    if (req->Attributes & CONF_ENABLE_DMA)
+	s->socket.flags |= SS_DMA_MODE;
+    if (req->Attributes & CONF_ENABLE_SPKR)
+	s->socket.flags |= SS_SPKR_ENA;
+    if (req->Attributes & CONF_ENABLE_IRQ)
+	s->socket.io_irq = s->irq.AssignedIRQ;
+    else
+	s->socket.io_irq = 0;
+    s->ss_entry(s->sock, SS_SetSocket, &s->socket);
+    s->lock_count++;
+    
+    /* Set up CIS configuration registers */
+    base = c->ConfigBase = req->ConfigBase;
+    c->Present = c->CardValues = req->Present;
+    if (req->Present & PRESENT_COPY) {
+	c->Copy = req->Copy;
+	write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
+    }
+    if (req->Present & PRESENT_OPTION) {
+	if (s->functions == 1)
+	    c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+	else {
+	    c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
+	    c->Option |= COR_FUNC_ENA|COR_ADDR_DECODE|COR_IREQ_ENA;
+	}
+	if (c->state & CONFIG_IRQ_REQ)
+	    if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
+		c->Option |= COR_LEVEL_REQ;
+	write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+	udelay(40*1000);
+    }
+    if (req->Present & PRESENT_STATUS) {
+	c->Status = req->Status;
+	write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
+    }
+    if (req->Present & PRESENT_PIN_REPLACE) {
+	c->Pin = req->Pin;
+	write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
+    }
+    if (req->Present & PRESENT_EXT_STATUS) {
+	c->ExtStatus = req->ExtStatus;
+	write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
+    }
+    if (req->Present & PRESENT_IOBASE_0) {
+	i = c->io.BasePort1 & 0xff;
+	write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &i);
+	i = (c->io.BasePort1 >> 8) & 0xff;
+	write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &i);
+    }
+    if (req->Present & PRESENT_IOSIZE) {
+	i = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+	write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &i);
+    }
+    
+    /* Configure I/O windows */
+    if (c->state & CONFIG_IO_REQ) {
+	iomap.speed = io_speed;
+	for (i = 0; i < MAX_IO_WIN; i++)
+	    if (s->io[i].NumPorts != 0) {
+		iomap.map = i;
+		iomap.flags = MAP_ACTIVE;
+		switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+		case IO_DATA_PATH_WIDTH_16:
+		    iomap.flags |= MAP_16BIT; break;
+		case IO_DATA_PATH_WIDTH_AUTO:
+		    iomap.flags |= MAP_AUTOSZ; break;
+		default:
+		    break;
+		}
+		iomap.start = s->io[i].BasePort;
+		iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+		s->ss_entry(s->sock, SS_SetIOMap, &iomap);
+		s->io[i].Config++;
+	    }
+    }
+    
+    c->state |= CONFIG_LOCKED;
+    handle->state |= CLIENT_CONFIG_LOCKED;
+    return CS_SUCCESS;
+} /* request_configuration */
+
+/*======================================================================
+  
+    Request_io() reserves ranges of port addresses for a socket.
+    I have not implemented range sharing or alias addressing.
+    
+======================================================================*/
+
+static int request_io(client_handle_t handle, io_req_t *req)
+{
+    socket_info_t *s;
+    config_t *c;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+
+    if (handle->state & CLIENT_CARDBUS) {
+#ifdef CONFIG_CARDBUS
+	int ret = cb_config(s);
+	if (ret == CS_SUCCESS)
+	    handle->state |= CLIENT_IO_REQ;
+	return ret;
+#else
+	return CS_UNSUPPORTED_FUNCTION;
+#endif
+    }
+
+    if (!req)
+	return CS_UNSUPPORTED_MODE;
+    c = CONFIG(handle);
+    if (c->state & CONFIG_LOCKED)
+	return CS_CONFIGURATION_LOCKED;
+    if (c->state & CONFIG_IO_REQ)
+	return CS_IN_USE;
+    if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
+	return CS_BAD_ATTRIBUTE;
+    if ((req->NumPorts2 > 0) &&
+	(req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
+	return CS_BAD_ATTRIBUTE;
+
+    if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
+		       req->NumPorts1, handle->dev_info))
+	return CS_IN_USE;
+
+    if (req->NumPorts2) {
+	if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+			   req->NumPorts2, handle->dev_info)) {
+	    release_io_space(s, req->BasePort1, req->NumPorts1);
+	    return CS_IN_USE;
+	}
+    }
+
+    c->io = *req;
+    c->state |= CONFIG_IO_REQ;
+    handle->state |= CLIENT_IO_REQ;
+    return CS_SUCCESS;
+} /* request_io */
+
+/*======================================================================
+
+    Request_irq() reserves an irq for this client.
+
+    Also, since Linux only reserves irq's when they are actually
+    hooked, we don't guarantee that an irq will still be available
+    when the configuration is locked.  Now that I think about it,
+    there might be a way to fix this using a dummy handler.
+    
+======================================================================*/
+
+static int cs_request_irq(client_handle_t handle, irq_req_t *req)
+{
+    socket_info_t *s;
+    config_t *c;
+    int try, ret = 0, irq = 0;
+    u_int mask;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    c = CONFIG(handle);
+    if (c->state & CONFIG_LOCKED)
+	return CS_CONFIGURATION_LOCKED;
+    if (c->state & CONFIG_IRQ_REQ)
+	return CS_IN_USE;
+    
+    /* Short cut: if the interrupt is PCI, there are no options */
+    if (s->cap.irq_mask == (1 << s->cap.pci_irq))
+	irq = s->cap.pci_irq;
+#ifdef CONFIG_ISA
+    else if (s->irq.AssignedIRQ != 0) {
+	/* If the interrupt is already assigned, it must match */
+	irq = s->irq.AssignedIRQ;
+	if (req->IRQInfo1 & IRQ_INFO2_VALID) {
+	    mask = req->IRQInfo2 & s->cap.irq_mask;
+	    ret = ((mask >> irq) & 1) ? 0 : CS_BAD_ARGS;
+	} else
+	    ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS;
+    } else {
+	ret = CS_IN_USE;
+	if (req->IRQInfo1 & IRQ_INFO2_VALID) {
+	    mask = req->IRQInfo2 & s->cap.irq_mask;
+	    mask &= ~(1 << s->cap.pci_irq);
+	    for (try = 0; try < 2; try++) {
+		for (irq = 0; irq < 32; irq++)
+		    if ((mask >> irq) & 1) {
+			ret = try_irq(req->Attributes, irq, try);
+			if (ret == 0) break;
+		    }
+		if (ret == 0) break;
+	    }
+	} else {
+	    irq = req->IRQInfo1 & IRQ_MASK;
+	    ret = try_irq(req->Attributes, irq, 1);
+	}
+    }
+#endif
+    if (ret != 0) return ret;
+
+    if (req->Attributes & IRQ_HANDLE_PRESENT) {
+	if (bus_request_irq(s->cap.bus, irq, req->Handler,
+			    ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || 
+			     (s->functions > 1) ||
+			     (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0,
+			    handle->dev_info, req->Instance))
+	    return CS_IN_USE;
+    }
+
+    c->irq.Attributes = req->Attributes;
+    s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+    s->irq.Config++;
+    
+    c->state |= CONFIG_IRQ_REQ;
+    handle->state |= CLIENT_IRQ_REQ;
+    return CS_SUCCESS;
+} /* cs_request_irq */
+
+/*======================================================================
+
+    Request_window() establishes a mapping between card memory space
+    and system memory space.
+
+======================================================================*/
+
+static int request_window(client_handle_t *handle, win_req_t *req)
+{
+    socket_info_t *s;
+    window_t *win;
+    int w;
+    
+    if (CHECK_HANDLE(*handle))
+	return CS_BAD_HANDLE;
+    s = SOCKET(*handle);
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    if (req->Attributes & (WIN_PAGED | WIN_SHARED))
+	return CS_BAD_ATTRIBUTE;
+
+    for (w = 0; w < MAX_WIN; w++)
+	if (!(s->state & SOCKET_WIN_REQ(w))) break;
+    if (w == MAX_WIN)
+	return CS_OUT_OF_RESOURCE;
+
+    /* Window size defaults to smallest available */
+    if (req->Size == 0)
+	req->Size = s->cap.map_size;
+    
+    /* Allocate system memory window */
+    win = &s->win[w];
+    win->magic = WINDOW_MAGIC;
+    win->index = w;
+    win->handle = *handle;
+    win->sock = s;
+    win->base = req->Base;
+    win->size = req->Size;
+    if (find_mem_region(&win->base, win->size, (*handle)->dev_info,
+			((s->cap.features & SS_CAP_MEM_ALIGN) ?
+			 req->Size : s->cap.map_size),
+			(req->Attributes & WIN_MAP_BELOW_1MB) ||
+			!(s->cap.features & SS_CAP_PAGE_REGS)))
+	return CS_IN_USE;
+    req->Base = win->base;
+    (*handle)->state |= CLIENT_WIN_REQ(w);
+
+    /* Configure the socket controller */
+    win->ctl.map = w+1;
+    win->ctl.flags = 0;
+    win->ctl.speed = req->AccessSpeed;
+    if (req->Attributes & WIN_MEMORY_TYPE)
+	win->ctl.flags |= MAP_ATTRIB;
+    if (req->Attributes & WIN_ENABLE)
+	win->ctl.flags |= MAP_ACTIVE;
+    if (req->Attributes & WIN_DATA_WIDTH)
+	win->ctl.flags |= MAP_16BIT;
+    if (req->Attributes & WIN_USE_WAIT)
+	win->ctl.flags |= MAP_USE_WAIT;
+    win->ctl.sys_start = req->Base;
+    win->ctl.sys_stop = req->Base + req->Size-1;
+    win->ctl.card_start = 0;
+    if (s->ss_entry(s->sock, SS_SetMemMap, &win->ctl) != 0)
+	return CS_BAD_ARGS;
+    s->state |= SOCKET_WIN_REQ(w);
+
+    /* Return window handle */
+    *handle = (client_handle_t)win;
+    
+    return CS_SUCCESS;
+} /* request_window */
+
+/*======================================================================
+
+    I'm not sure which "reset" function this is supposed to use,
+    but for now, it uses the low-level interface's reset, not the
+    CIS register.
+    
+======================================================================*/
+
+static int reset_card(client_handle_t handle, client_req_t *req)
+{
+    int i, ret;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    if (s->state & SOCKET_RESET_PENDING)
+	return CS_IN_USE;
+    s->state |= SOCKET_RESET_PENDING;
+
+    ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+    if (ret != 0) {
+	s->state &= ~SOCKET_RESET_PENDING;
+	handle->event_callback_args.info = (void *)(u_long)ret;
+	EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+    } else {
+	DEBUG(1, "cs: resetting socket %d\n", i);
+	send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+	s->reset_handle = handle;
+	reset_socket(i);
+    }
+    return CS_SUCCESS;
+} /* reset_card */
+
+/*======================================================================
+
+    These shut down or wake up a socket.  They are sort of user
+    initiated versions of the APM suspend and resume actions.
+    
+======================================================================*/
+
+static int suspend_card(client_handle_t handle, client_req_t *req)
+{
+    int i;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    if (s->state & SOCKET_SUSPEND)
+	return CS_IN_USE;
+
+    DEBUG(1, "cs: suspending socket %d\n", i);
+    send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+    s->ss_entry(s->sock, SS_SetSocket, &dead_socket);
+    s->state |= SOCKET_SUSPEND;
+
+    return CS_SUCCESS;
+} /* suspend_card */
+
+static int resume_card(client_handle_t handle, client_req_t *req)
+{
+    int i;
+    socket_info_t *s;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+    if (!(s->state & SOCKET_SUSPEND))
+	return CS_IN_USE;
+
+    DEBUG(1, "cs: waking up socket %d\n", i);
+    setup_socket(i);
+
+    return CS_SUCCESS;
+} /* resume_card */
+
+/*======================================================================
+
+    These handle user requests to eject or insert a card.
+    
+======================================================================*/
+
+static int eject_card(client_handle_t handle, client_req_t *req)
+{
+    int i, ret;
+    socket_info_t *s;
+    u_long flags;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (!(s->state & SOCKET_PRESENT))
+	return CS_NO_CARD;
+
+    DEBUG(1, "cs: user eject request on socket %d\n", i);
+
+    ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+    if (ret != 0)
+	return ret;
+
+    spin_lock_irqsave(&s->lock, flags);
+    do_shutdown(s);
+    spin_unlock_irqrestore(&s->lock, flags);
+    
+    return CS_SUCCESS;
+    
+} /* eject_card */
+
+static int insert_card(client_handle_t handle, client_req_t *req)
+{
+    int i, status;
+    socket_info_t *s;
+    u_long flags;
+    
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    i = handle->Socket; s = socket_table[i];
+    if (s->state & SOCKET_PRESENT)
+	return CS_IN_USE;
+
+    DEBUG(1, "cs: user insert request on socket %d\n", i);
+
+    spin_lock_irqsave(&s->lock, flags);
+    if (!(s->state & SOCKET_SETUP_PENDING)) {
+	s->state |= SOCKET_SETUP_PENDING;
+	spin_unlock_irqrestore(&s->lock, flags);
+	s->ss_entry(i, SS_GetStatus, &status);
+	if (status & SS_DETECT)
+	    setup_socket(i);
+	else {
+	    s->state &= ~SOCKET_SETUP_PENDING;
+	    return CS_NO_CARD;
+	}
+    } else
+	spin_unlock_irqrestore(&s->lock, flags);
+
+    return CS_SUCCESS;
+} /* insert_card */
+
+/*======================================================================
+
+    Maybe this should send a CS_EVENT_CARD_INSERTION event if we
+    haven't sent one to this client yet?
+    
+======================================================================*/
+
+static int set_event_mask(client_handle_t handle, eventmask_t *mask)
+{
+    u_int events, bit;
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    if (handle->Attributes & CONF_EVENT_MASK_VALID)
+	return CS_BAD_SOCKET;
+    handle->EventMask = mask->EventMask;
+    events = handle->PendingEvents & handle->EventMask;
+    handle->PendingEvents -= events;
+    while (events != 0) {
+	bit = ((events ^ (events-1)) + 1) >> 1;
+	EVENT(handle, bit, CS_EVENT_PRI_LOW);
+	events -= bit;
+    }
+    return CS_SUCCESS;
+} /* set_event_mask */
+
+/*====================================================================*/
+
+static int report_error(client_handle_t handle, error_info_t *err)
+{
+    int i;
+    char *serv;
+
+    if (CHECK_HANDLE(handle))
+	printk(KERN_NOTICE);
+    else
+	printk(KERN_NOTICE "%s: ", handle->dev_info);
+    
+    for (i = 0; i < SERVICE_COUNT; i++)
+	if (service_table[i].key == err->func) break;
+    if (i < SERVICE_COUNT)
+	serv = service_table[i].msg;
+    else
+	serv = "Unknown service number";
+
+    for (i = 0; i < ERROR_COUNT; i++)
+	if (error_table[i].key == err->retcode) break;
+    if (i < ERROR_COUNT)
+	printk("%s: %s\n", serv, error_table[i].msg);
+    else
+	printk("%s: Unknown error code %#x\n", serv, err->retcode);
+
+    return CS_SUCCESS;
+} /* report_error */
+
+/*====================================================================*/
+
+int CardServices(int func, void *a1, void *a2, void *a3)
+{
+
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 1) {
+	int i;
+	for (i = 0; i < SERVICE_COUNT; i++)
+	    if (service_table[i].key == func) break;
+	if (i < SERVICE_COUNT)
+	    printk(KERN_DEBUG "cs: CardServices(%s, 0x%p, 0x%p)\n",
+		   service_table[i].msg, a1, a2);
+	else
+	    printk(KERN_DEBUG "cs: CardServices(Unknown func %d, "
+		   "0x%p, 0x%p)\n", func, a1, a2);
+    }
+#endif
+    switch (func) {
+    case AccessConfigurationRegister:
+	return access_configuration_register(a1, a2); break;
+    case AdjustResourceInfo:
+	return adjust_resource_info(a1, a2); break;
+    case CheckEraseQueue:
+	return check_erase_queue(a1); break;
+    case CloseMemory:
+	return close_memory(a1); break;
+    case CopyMemory:
+	return copy_memory(a1, a2); break;
+    case DeregisterClient:
+	return deregister_client(a1); break;
+    case DeregisterEraseQueue:
+	return deregister_erase_queue(a1); break;
+    case GetFirstClient:
+	return get_first_client(a1, a2); break;
+    case GetCardServicesInfo:
+	return get_card_services_info(a1); break;
+    case GetConfigurationInfo:
+	return get_configuration_info(a1, a2); break;
+    case GetNextClient:
+	return get_next_client(a1, a2); break;
+    case GetFirstRegion:
+	return get_first_region(a1, a2); break;
+    case GetFirstTuple:
+	return get_first_tuple(a1, a2); break;
+    case GetNextRegion:
+	return get_next_region(a1, a2); break;
+    case GetNextTuple:
+	return get_next_tuple(a1, a2); break;
+    case GetStatus:
+	return get_status(a1, a2); break;
+    case GetTupleData:
+	return get_tuple_data(a1, a2); break;
+    case MapMemPage:
+	return map_mem_page(a1, a2); break;
+    case ModifyConfiguration:
+	return modify_configuration(a1, a2); break;
+    case ModifyWindow:
+	return modify_window(a1, a2); break;
+    case OpenMemory:
+	return open_memory(a1, a2);
+    case ParseTuple:
+	return parse_tuple(a1, a2, a3); break;
+    case ReadMemory:
+	return read_memory(a1, a2, a3); break;
+    case RegisterClient:
+	return register_client(a1, a2); break;
+    case RegisterEraseQueue:
+	return register_erase_queue(a1, a2); break;
+    case RegisterMTD:
+	return register_mtd(a1, a2); break;
+    case ReleaseConfiguration:
+	return release_configuration(a1, a2); break;
+    case ReleaseIO:
+	return release_io(a1, a2); break;
+    case ReleaseIRQ:
+	return cs_release_irq(a1, a2); break;
+    case ReleaseWindow:
+	return release_window(a1); break;
+    case RequestConfiguration:
+	return request_configuration(a1, a2); break;
+    case RequestIO:
+	return request_io(a1, a2); break;
+    case RequestIRQ:
+	return cs_request_irq(a1, a2); break;
+    case RequestWindow:
+	return request_window(a1, a2); break;
+    case ResetCard:
+	return reset_card(a1, a2); break;
+    case SetEventMask:
+	return set_event_mask(a1, a2); break;
+    case ValidateCIS:
+	return validate_cis(a1, a2); break;
+    case WriteMemory:
+	return write_memory(a1, a2, a3); break;
+    case BindDevice:
+	return bind_device(a1); break;
+    case BindMTD:
+	return bind_mtd(a1); break;
+    case ReportError:
+	return report_error(a1, a2); break;
+    case SuspendCard:
+	return suspend_card(a1, a2); break;
+    case ResumeCard:
+	return resume_card(a1, a2); break;
+    case EjectCard:
+	return eject_card(a1, a2); break;
+    case InsertCard:
+	return insert_card(a1, a2); break;
+    case ReplaceCIS:
+	return replace_cis(a1, a2); break;
+    case GetFirstWindow:
+	return get_first_window(a1, a2); break;
+    case GetNextWindow:
+	return get_next_window(a1, a2); break;
+    case GetMemPage:
+	return get_mem_page(a1, a2); break;
+    default:
+	return CS_UNSUPPORTED_FUNCTION; break;
+    }
+    
+} /* CardServices */
+
+/*======================================================================
+
+    OS-specific module glue goes here
+    
+======================================================================*/
+
+EXPORT_SYMBOL(register_ss_entry);
+EXPORT_SYMBOL(unregister_ss_entry);
+EXPORT_SYMBOL(CardServices);
+EXPORT_SYMBOL(MTDHelperEntry);
+
+static int pcmcia_cs_init(void)
+{
+    printk(KERN_INFO "%s\n", release);
+    printk(KERN_INFO "  %s\n", options);
+    DEBUG(0, "%s\n", version);
+#ifdef CONFIG_APM
+    if (do_apm)
+	apm_register_callback(&handle_apm_event);
+#endif
+#ifdef CONFIG_PROC_FS
+    proc_pccard = create_proc_entry("pccard", S_IFDIR, proc_bus);
+#endif
+    return 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	return pcmcia_cs_init();
+}
+
+void cleanup_module(void)
+{
+    printk(KERN_INFO "unloading PCMCIA Card Services\n");
+#ifdef CONFIG_PROC_FS
+    if (proc_pccard) {
+	remove_proc_entry("pccard", proc_bus);
+    }
+#endif
+#ifdef CONFIG_APM
+    if (do_apm)
+	apm_unregister_callback(&handle_apm_event);
+#endif
+    release_resource_db();
+}
+
+#else
+
+extern int pcmcia_ds_init(void);
+extern int pcmcia_i82365_init(void);
+
+int pcmcia_init(void)
+{
+	/* Start core services */
+	pcmcia_cs_init();
+
+	/* Load the socket drivers */
+	pcmcia_i82365_init();
+
+	/* Get the ball rolling.. */
+	return pcmcia_ds_init();
+}
+
+#endif
+
+/*====================================================================*/
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/cs_internal.h linux/drivers/pcmcia/cs_internal.h
--- v2.3.16/linux/drivers/pcmcia/cs_internal.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/cs_internal.h	Tue Sep  7 11:48:46 1999
@@ -0,0 +1,280 @@
+/*
+ * cs_internal.h 1.43 1999/09/07 15:19:04
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ */
+
+#ifndef _LINUX_CS_INTERNAL_H
+#define _LINUX_CS_INTERNAL_H
+
+typedef struct erase_busy_t {
+    eraseq_entry_t	*erase;
+    client_handle_t	client;
+    struct timer_list	timeout;
+    struct erase_busy_t	*prev, *next;
+} erase_busy_t;
+
+#define ERASEQ_MAGIC	0xFA67
+typedef struct eraseq_t {
+    u_short		eraseq_magic;
+    client_handle_t	handle;
+    int			count;
+    eraseq_entry_t	*entry;
+} eraseq_t;
+
+#define CLIENT_MAGIC 	0x51E6
+typedef struct client_t {
+    u_short		client_magic;
+    socket_t		Socket;
+    u_char		Function;
+    dev_info_t		dev_info;
+    u_int		Attributes;
+    u_int		state;
+    event_t		EventMask, PendingEvents;
+    int (*event_handler)(event_t event, int priority,
+			 event_callback_args_t *);
+    event_callback_args_t event_callback_args;
+    struct client_t 	*next;
+    u_int		mtd_count;
+    wait_queue_head_t	mtd_req;
+    erase_busy_t	erase_busy;
+} client_t;
+
+/* Flags in client state */
+#define CLIENT_CONFIG_LOCKED	0x0001
+#define CLIENT_IRQ_REQ		0x0002
+#define CLIENT_IO_REQ		0x0004
+#define CLIENT_UNBOUND		0x0008
+#define CLIENT_STALE		0x0010
+#define CLIENT_WIN_REQ(i)	(0x20<<(i))
+#define CLIENT_CARDBUS		0x8000
+
+typedef struct io_window_t {
+    u_int		Attributes;
+    ioaddr_t		BasePort, NumPorts;
+    ioaddr_t		InUse, Config;
+} io_window_t;
+
+#define WINDOW_MAGIC	0xB35C
+typedef struct window_t {
+    u_short		magic;
+    u_short		index;
+    client_handle_t	handle;
+    struct socket_info_t *sock;
+    u_long		base;
+    u_long		size;
+    pccard_mem_map	ctl;
+} window_t;
+
+#define REGION_MAGIC	0xE3C9
+typedef struct region_t {
+    u_short		region_magic;
+    u_short		state;
+    dev_info_t		dev_info;
+    client_handle_t	mtd;
+    u_int		MediaID;
+    region_info_t	info;
+} region_t;
+
+#define REGION_STALE	0x01
+
+/* Each card function gets one of these guys */
+typedef struct config_t {
+    u_int		state;
+    u_int		Attributes;
+    u_int		Vcc, Vpp1, Vpp2;
+    u_int		IntType;
+    u_int		ConfigBase;
+    u_char		Status, Pin, Copy, Option, ExtStatus;
+    u_int		Present;
+    u_int		CardValues;
+    io_req_t		io;
+    struct {
+	u_int		Attributes;
+    } irq;
+} config_t;
+
+/* Maximum number of IO windows per socket */
+#define MAX_IO_WIN 2
+
+/* Maximum number of memory windows per socket */
+#define MAX_WIN 4
+
+/* The size of the CIS cache */
+#define MAX_CIS_TABLE	64
+#define MAX_CIS_DATA	512
+
+typedef struct socket_info_t {
+    spinlock_t			lock;
+    ss_entry_t			ss_entry;
+    u_int			sock;
+    socket_state_t		socket;
+    socket_cap_t		cap;
+    u_int			state;
+    u_short			functions;
+    u_short			lock_count;
+    client_handle_t		clients;
+    u_int			real_clients;
+    client_handle_t		reset_handle;
+    struct timer_list		setup, shutdown;
+    u_long			unreset_timeout;
+    pccard_mem_map		cis_mem;
+    u_char			*cis_virt;
+    config_t			*config;
+#ifdef CONFIG_CARDBUS
+    u_int			cb_cis_space;
+    cb_bridge_map		cb_cis_map;
+    u_char			*cb_cis_virt;
+    struct cb_config_t		*cb_config;
+#endif
+    struct {
+	u_int			AssignedIRQ;
+	u_int			Config;
+    } irq;
+    io_window_t			io[MAX_IO_WIN];
+    window_t			win[MAX_WIN];
+    region_t			*c_region, *a_region;
+    erase_busy_t		erase_busy;
+    int				cis_used;
+    struct {
+	u_int			addr;
+	u_short			len;
+	u_short			attr;
+    }				cis_table[MAX_CIS_TABLE];
+    char			cis_cache[MAX_CIS_DATA];
+    u_int			fake_cis_len;
+    char			*fake_cis;
+#ifdef CONFIG_PROC_FS
+    struct proc_dir_entry	*proc;
+#endif
+} socket_info_t;
+
+/* Flags in config state */
+#define CONFIG_LOCKED		0x01
+#define CONFIG_IRQ_REQ		0x02
+#define CONFIG_IO_REQ		0x04
+
+/* Flags in socket state */
+#define SOCKET_PRESENT		0x0008
+#define SOCKET_SETUP_PENDING	0x0010
+#define SOCKET_SHUTDOWN_PENDING	0x0020
+#define SOCKET_RESET_PENDING	0x0040
+#define SOCKET_SUSPEND		0x0080
+#define SOCKET_WIN_REQ(i)	(0x0100<<(i))
+#define SOCKET_IO_REQ(i)	(0x1000<<(i))
+#define SOCKET_REGION_INFO	0x4000
+#define SOCKET_CARDBUS		0x8000
+
+#define CHECK_HANDLE(h) \
+    (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
+
+#define CHECK_SOCKET(s) \
+    (((s) >= sockets) || (socket_table[s]->ss_entry == NULL))
+
+#define SOCKET(h) (socket_table[(h)->Socket])
+#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
+
+#define CHECK_REGION(r) \
+    (((r) == NULL) || ((r)->region_magic != REGION_MAGIC))
+
+#define CHECK_ERASEQ(q) \
+    (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC))
+
+#define EVENT(h, e, p) \
+    ((h)->event_handler((e), (p), &(h)->event_callback_args))
+
+/* In cardbus.c */
+int cb_alloc(socket_info_t *s);
+void cb_free(socket_info_t *s);
+int cb_config(socket_info_t *s);
+void cb_release(socket_info_t *s);
+void cb_enable(socket_info_t *s);
+void cb_disable(socket_info_t *s);
+void read_cb_mem(socket_info_t *s, u_char fn, int space,
+		 u_int addr, u_int len, void *ptr);
+int cb_setup_cis_mem(socket_info_t *s, int space);
+void cb_release_cis_mem(socket_info_t *s);
+
+/* In cistpl.c */
+void read_cis_mem(socket_info_t *s, int attr,
+		  u_int addr, u_int len, void *ptr);
+void write_cis_mem(socket_info_t *s, int attr,
+		   u_int addr, u_int len, void *ptr);
+int setup_cis_mem(socket_info_t *s);
+void release_cis_mem(socket_info_t *s);
+int verify_cis_cache(socket_info_t *s);
+void preload_cis_cache(socket_info_t *s);
+int get_first_tuple(client_handle_t handle, tuple_t *tuple);
+int get_next_tuple(client_handle_t handle, tuple_t *tuple);
+int get_tuple_data(client_handle_t handle, tuple_t *tuple);
+int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse);
+int validate_cis(client_handle_t handle, cisinfo_t *info);
+int replace_cis(client_handle_t handle, cisdump_t *cis);
+int read_tuple(client_handle_t handle, cisdata_t code, void *parse);
+
+/* In bulkmem.c */
+void retry_erase_list(struct erase_busy_t *list, u_int cause);
+int get_first_region(client_handle_t handle, region_info_t *rgn);
+int get_next_region(client_handle_t handle, region_info_t *rgn);
+int register_mtd(client_handle_t handle, mtd_reg_t *reg);
+int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header);
+int deregister_erase_queue(eraseq_handle_t eraseq);
+int check_erase_queue(eraseq_handle_t eraseq);
+int open_memory(client_handle_t *handle, open_mem_t *open);
+int close_memory(memory_handle_t handle);
+int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
+int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf);
+int copy_memory(memory_handle_t handle, copy_op_t *req);
+
+/* In rsrc_mgr */
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+		  int force_low);
+int find_io_region(ioaddr_t *base, ioaddr_t num, char *name);
+int find_mem_region(u_long *base, u_long num, char *name,
+		    u_long align, int force_low);
+int try_irq(u_int Attributes, int irq, int specific);
+void undo_irq(u_int Attributes, int irq);
+int adjust_resource_info(client_handle_t handle, adjust_t *adj);
+void release_resource_db(void);
+int proc_read_io(char *buf, char **start, off_t pos,
+		 int count, int *eof, void *data);
+int proc_read_mem(char *buf, char **start, off_t pos,
+		  int count, int *eof, void *data);
+
+/* in pnp components */
+int proc_read_irq(char *buf, char **start, off_t pos,
+		  int count, int *eof, void *data);
+void pnp_bios_init(void);
+void pnp_proc_init(void);
+void pnp_proc_done(void);
+void pnp_rsrc_init(void);
+void pnp_rsrc_done(void);
+
+#define MAX_SOCK 8
+extern socket_t sockets;
+extern socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry *proc_pccard;
+#endif
+
+#ifdef PCMCIA_DEBUG
+extern int pc_debug;
+#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(args); } while (0)
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+#endif /* _LINUX_CS_INTERNAL_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/ds.c linux/drivers/pcmcia/ds.c
--- v2.3.16/linux/drivers/pcmcia/ds.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/ds.c	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,898 @@
+/*======================================================================
+
+    PC Card Driver Services
+    
+    ds.c 1.96 1999/09/02 18:35:34
+    
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/ioctl.h>
+#include <linux/poll.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static const char *version =
+"ds.c 1.96 1999/09/02 18:35:34 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+    dev_info_t		dev_info;
+    int			use_count;
+    dev_link_t		*(*attach)(void);
+    void		(*detach)(dev_link_t *);
+    struct driver_info_t *next;
+} driver_info_t;
+
+typedef struct socket_bind_t {
+    driver_info_t	*driver;
+    dev_link_t		*instance;
+    struct socket_bind_t *next;
+} socket_bind_t;
+
+/* Device user information */
+#define MAX_EVENTS	32
+#define USER_MAGIC	0x7ea4
+#define CHECK_USER(u) \
+    (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
+typedef struct user_info_t {
+    u_int		user_magic;
+    int			event_head, event_tail;
+    event_t		event[MAX_EVENTS];
+    struct user_info_t	*next;
+} user_info_t;
+
+/* Socket state information */
+typedef struct socket_info_t {
+    client_handle_t	handle;
+    int			state;
+    user_info_t		*user;
+    int			req_pending, req_result;
+    wait_queue_head_t	queue, request;
+    struct timer_list	removal;
+    socket_bind_t	*bind;
+} socket_info_t;
+
+#define SOCKET_PRESENT		0x01
+#define SOCKET_BUSY		0x02
+#define SOCKET_REMOVAL_PENDING	0x10
+
+/*====================================================================*/
+
+/* Device driver ID passed to Card Services */
+static dev_info_t dev_info = "Driver Services";
+
+/* Linked list of all registered device drivers */
+static driver_info_t *root_driver = NULL;
+
+static int sockets = 0, major_dev = -1;
+static socket_info_t *socket_table = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    Register_pccard_driver() and unregister_pccard_driver() are used
+    tell Driver Services that a PC Card client driver is available to
+    be bound to sockets.
+    
+======================================================================*/
+
+int register_pccard_driver(dev_info_t *dev_info,
+			   dev_link_t *(*attach)(void),
+			   void (*detach)(dev_link_t *))
+{
+    driver_info_t *driver;
+    socket_bind_t *b;
+    int i;
+
+    DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
+    for (driver = root_driver; driver; driver = driver->next)
+	if (strncmp((char *)dev_info, (char *)driver->dev_info,
+		    DEV_NAME_LEN) == 0)
+	    break;
+    if (!driver) {
+	driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+	strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN);
+	driver->use_count = 0;
+	driver->next = root_driver;
+	root_driver = driver;
+    }
+
+    driver->attach = attach;
+    driver->detach = detach;
+    if (driver->use_count == 0) return 0;
+    
+    /* Instantiate any already-bound devices */
+    for (i = 0; i < sockets; i++)
+	for (b = socket_table[i].bind; b; b = b->next) {
+	    if (b->driver != driver) continue;
+	    b->instance = driver->attach();
+	    if (b->instance == NULL)
+		printk(KERN_NOTICE "ds: unable to create instance "
+		       "of '%s'!\n", driver->dev_info);
+	}
+    
+    return 0;
+} /* register_pccard_driver */
+
+/*====================================================================*/
+
+int unregister_pccard_driver(dev_info_t *dev_info)
+{
+    driver_info_t *target, **d = &root_driver;
+    socket_bind_t *b;
+    int i;
+    
+    DEBUG(0, "ds: unregister_pccard_driver('%s')\n",
+	  (char *)dev_info);
+    while ((*d) && (strncmp((*d)->dev_info, (char *)dev_info,
+			    DEV_NAME_LEN) != 0))
+	d = &(*d)->next;
+    if (*d == NULL)
+	return -1;
+    
+    target = *d;
+    if (target->use_count == 0) {
+	*d = target->next;
+	kfree(target);
+    } else {
+	/* Blank out any left-over device instances */
+	target->attach = NULL; target->detach = NULL;
+	for (i = 0; i < sockets; i++)
+	    for (b = socket_table[i].bind; b; b = b->next)
+		if (b->driver == target) b->instance = NULL;
+    }
+    return 0;
+} /* unregister_pccard_driver */
+
+/*======================================================================
+
+    These manage a ring buffer of events pending for one user process
+    
+======================================================================*/
+
+static int queue_empty(user_info_t *user)
+{
+    return (user->event_head == user->event_tail);
+}
+
+static event_t get_queued_event(user_info_t *user)
+{
+    user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    return user->event[user->event_tail];
+}
+
+static void queue_event(user_info_t *user, event_t event)
+{
+    user->event_head = (user->event_head+1) % MAX_EVENTS;
+    if (user->event_head == user->event_tail)
+	user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+    user->event[user->event_head] = event;
+}
+
+static void handle_event(socket_info_t *s, event_t event)
+{
+    user_info_t *user;
+    for (user = s->user; user; user = user->next)
+	queue_event(user, event);
+    wake_up_interruptible(&s->queue);
+}
+
+static int handle_request(socket_info_t *s, event_t event)
+{
+    if (s->req_pending != 0)
+	return CS_IN_USE;
+    if (s->state & SOCKET_BUSY)
+	s->req_pending = 1;
+    handle_event(s, event);
+    if (s->req_pending > 0) {
+	interruptible_sleep_on(&s->request);
+	if (signal_pending(current))
+	    return CS_IN_USE;
+	else
+	    return s->req_result;
+    }
+    return CS_SUCCESS;
+}
+
+static void handle_removal(u_long sn)
+{
+    socket_info_t *s = &socket_table[sn];
+    handle_event(s, CS_EVENT_CARD_REMOVAL);
+    s->state &= ~SOCKET_REMOVAL_PENDING;
+}
+
+/*======================================================================
+
+    The card status event handler.
+    
+======================================================================*/
+
+static int ds_event(event_t event, int priority,
+		    event_callback_args_t *args)
+{
+    socket_info_t *s;
+    int i;
+
+    DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n",
+	  event, priority, args->client_handle);
+    s = args->client_data;
+    i = s - socket_table;
+    
+    switch (event) {
+	
+    case CS_EVENT_CARD_REMOVAL:
+	s->state &= ~SOCKET_PRESENT;
+	if (!(s->state & SOCKET_REMOVAL_PENDING)) {
+	    s->state |= SOCKET_REMOVAL_PENDING;
+	    s->removal.expires = jiffies + HZ/10;
+	    add_timer(&s->removal);
+	}
+	break;
+	
+    case CS_EVENT_CARD_INSERTION:
+	s->state |= SOCKET_PRESENT;
+	handle_event(s, event);
+	break;
+
+    case CS_EVENT_EJECTION_REQUEST:
+	return handle_request(s, event);
+	break;
+	
+    default:
+	handle_event(s, event);
+	break;
+    }
+
+    return 0;
+} /* ds_event */
+
+/*======================================================================
+
+    bind_mtd() connects a memory region with an MTD client.
+    
+======================================================================*/
+
+static int bind_mtd(int i, mtd_info_t *mtd_info)
+{
+    mtd_bind_t bind_req;
+    int ret;
+
+    bind_req.dev_info = &mtd_info->dev_info;
+    bind_req.Attributes = mtd_info->Attributes;
+    bind_req.Socket = i;
+    bind_req.CardOffset = mtd_info->CardOffset;
+    ret = CardServices(BindMTD, &bind_req);
+    if (ret != CS_SUCCESS) {
+	cs_error(NULL, BindMTD, ret);
+	printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d"
+	       " offset 0x%x\n",
+	       (char *)bind_req.dev_info, i, bind_req.CardOffset);
+	return -ENODEV;
+    }
+    return 0;
+} /* bind_mtd */
+
+/*======================================================================
+
+    bind_request() connects a socket to a particular client driver.
+    It looks up the specified device ID in the list of registered
+    drivers, binds it to the socket, and tries to create an instance
+    of the device.  unbind_request() deletes a driver instance.
+    
+======================================================================*/
+
+static int bind_request(int i, bind_info_t *bind_info)
+{
+    struct driver_info_t *driver;
+    socket_bind_t *b;
+    bind_req_t bind_req;
+    socket_info_t *s = &socket_table[i];
+    int ret;
+
+    DEBUG(2, "bind_request(%d, '%s')\n", i,
+	  (char *)bind_info->dev_info);
+    for (driver = root_driver; driver; driver = driver->next)
+	if (strcmp((char *)driver->dev_info,
+		   (char *)bind_info->dev_info) == 0)
+	    break;
+    if (driver == NULL) {
+	driver = kmalloc(sizeof(driver_info_t), GFP_KERNEL);
+	strncpy(driver->dev_info, bind_info->dev_info, DEV_NAME_LEN);
+	driver->use_count = 0;
+	driver->next = root_driver;
+	driver->attach = NULL; driver->detach = NULL;
+	root_driver = driver;
+    }
+
+    for (b = s->bind; b; b = b->next)
+	if (driver == b->driver)
+	    break;
+    if (b != NULL) {
+	bind_info->instance = b->instance;
+	return -EBUSY;
+    }
+
+    bind_req.Socket = i;
+    bind_req.Function = bind_info->function;
+    bind_req.dev_info = &driver->dev_info;
+    ret = CardServices(BindDevice, &bind_req);
+    if (ret != CS_SUCCESS) {
+	cs_error(NULL, BindDevice, ret);
+	printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
+	       (char *)dev_info, i);
+	return -ENODEV;
+    }
+
+    /* Add binding to list for this socket */
+    driver->use_count++;
+    b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
+    b->driver = driver;
+    b->instance = NULL;
+    b->next = s->bind;
+    s->bind = b;
+    
+    if (driver->attach) {
+	b->instance = driver->attach();
+	if (b->instance == NULL) {
+	    printk(KERN_NOTICE "ds: unable to create instance "
+		   "of '%s'!\n", (char *)bind_info->dev_info);
+	    return -ENODEV;
+	}
+    }
+    
+    return 0;
+} /* bind_request */
+
+/*====================================================================*/
+
+static int get_device_info(int i, bind_info_t *bind_info, int first)
+{
+    socket_info_t *s = &socket_table[i];
+    socket_bind_t *b;
+    dev_node_t *node;
+    
+    for (b = s->bind; b; b = b->next)
+	if (strcmp((char *)b->driver->dev_info,
+		   (char *)bind_info->dev_info) == 0)
+	    break;
+    if (b == NULL) return -ENODEV;
+    if ((b->instance == NULL) ||
+	(b->instance->state & DEV_CONFIG_PENDING))
+	return -EAGAIN;
+    if (first)
+	node = b->instance->dev;
+    else
+	for (node = b->instance->dev; node; node = node->next)
+	    if (node == bind_info->next) break;
+    if (node == NULL) return -ENODEV;
+
+    strncpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+    bind_info->name[DEV_NAME_LEN-1] = '\0';
+    bind_info->major = node->major;
+    bind_info->minor = node->minor;
+    bind_info->next = node->next;
+    
+    return 0;
+} /* get_device_info */
+
+/*====================================================================*/
+
+static int unbind_request(int i, bind_info_t *bind_info)
+{
+    socket_info_t *s = &socket_table[i];
+    socket_bind_t **b, *c;
+
+    DEBUG(2, "unbind_request(%d, '%s')\n", i,
+	  (char *)bind_info->dev_info);
+    for (b = &s->bind; *b; b = &(*b)->next)
+	if (strcmp((char *)(*b)->driver->dev_info,
+		   (char *)bind_info->dev_info) == 0)
+	    break;
+    if (*b == NULL)
+	return -ENODEV;
+    
+    c = *b;
+    c->driver->use_count--;
+    if (c->driver->detach) {
+	if (c->instance)
+	    c->driver->detach(c->instance);
+    } else {
+	if (c->driver->use_count == 0) {
+	    driver_info_t **d;
+	    for (d = &root_driver; *d; d = &((*d)->next))
+		if (c->driver == *d) break;
+	    *d = (*d)->next;
+	    kfree_s(c->driver, sizeof(driver_info_t));
+	}
+    }
+    *b = c->next;
+    kfree_s(c, sizeof(socket_bind_t));
+    
+    return 0;
+} /* unbind_request */
+
+/*======================================================================
+
+    The user-mode PC Card device interface
+
+======================================================================*/
+
+static int ds_open(struct inode *inode, struct file *file)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(0, "ds_open(socket %d)\n", i);
+    if ((i >= sockets) || (sockets == 0))
+	return -ENODEV;
+    s = &socket_table[i];
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+	if (s->state & SOCKET_BUSY)
+	    return -EBUSY;
+	else
+	    s->state |= SOCKET_BUSY;
+    }
+    
+    MOD_INC_USE_COUNT;
+    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+    user->event_tail = user->event_head = 0;
+    user->next = s->user;
+    user->user_magic = USER_MAGIC;
+    s->user = user;
+    file->private_data = user;
+    
+    if (s->state & SOCKET_PRESENT)
+	queue_event(user, CS_EVENT_CARD_INSERTION);
+    return 0;
+} /* ds_open */
+
+/*====================================================================*/
+
+static int ds_release(struct inode *inode, struct file *file)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user, **link;
+
+    DEBUG(0, "ds_release(socket %d)\n", i);
+    if ((i >= sockets) || (sockets == 0))
+	return 0;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+	return 0;
+
+    /* Unlink user data structure */
+    if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+	s->state &= ~SOCKET_BUSY;
+    file->private_data = NULL;
+    for (link = &s->user; *link; link = &(*link)->next)
+	if (*link == user) break;
+    if (link == NULL)
+	return 0;
+    *link = user->next;
+    user->user_magic = 0;
+    kfree_s(user, sizeof(user_info_t));
+    
+    MOD_DEC_USE_COUNT;
+    return 0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read(struct file *file, char *buf,
+			      size_t count, loff_t *ppos)
+{
+    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_read(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+	return -ENODEV;
+    if (count < 4)
+	return -EINVAL;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+	return -EIO;
+    
+    if (queue_empty(user)) {
+	interruptible_sleep_on(&s->queue);
+	if (signal_pending(current))
+	    return -EINTR;
+    }
+    put_user(get_queued_event(user), (int *)buf);
+    return 4;
+} /* ds_read */
+
+/*====================================================================*/
+
+static ssize_t ds_write(struct file *file, const char *buf,
+			       size_t count, loff_t *ppos)
+{
+    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_write(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+	return -ENODEV;
+    if (count != 4)
+	return -EINVAL;
+    if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+	return -EBADF;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+	return -EIO;
+
+    if (s->req_pending) {
+	s->req_pending--;
+	get_user(s->req_result, (int *)buf);
+	if ((s->req_result != 0) || (s->req_pending == 0))
+	    wake_up_interruptible(&s->request);
+    } else
+	return -EIO;
+
+    return 4;
+} /* ds_write */
+
+/*====================================================================*/
+
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+    socket_t i = MINOR(file->f_dentry->d_inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_poll(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+	return POLLERR;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+	return POLLERR;
+    poll_wait(file, &s->queue, wait);
+    if (!queue_empty(user))
+	return POLLIN | POLLRDNORM;
+    return 0;
+} /* ds_poll */
+
+/*====================================================================*/
+
+static int ds_ioctl(struct inode * inode, struct file * file,
+		    u_int cmd, u_long arg)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    u_int size;
+    int ret, err;
+    ds_ioctl_arg_t buf;
+
+    DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg);
+    
+    if ((i >= sockets) || (sockets == 0))
+	return -ENODEV;
+    s = &socket_table[i];
+    
+    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+    if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+
+    /* Permission check */
+    if (!(cmd & IOC_OUT) && !suser())
+	return -EPERM;
+	
+    if (cmd & IOC_IN) {
+	err = verify_area(VERIFY_READ, (char *)arg, size);
+	if (err) {
+	    DEBUG(3, "ds_ioctl(): verify_read = %d\n", err);
+	    return err;
+	}
+    }
+    if (cmd & IOC_OUT) {
+	err = verify_area(VERIFY_WRITE, (char *)arg, size);
+	if (err) {
+	    DEBUG(3, "ds_ioctl(): verify_write = %d\n", err);
+	    return err;
+	}
+    }
+    
+    err = ret = 0;
+    
+    if (cmd & IOC_IN) copy_from_user((char *)&buf, (char *)arg, size);
+    
+    switch (cmd) {
+    case DS_ADJUST_RESOURCE_INFO:
+	ret = CardServices(AdjustResourceInfo, s->handle, &buf.adjust);
+	break;
+    case DS_GET_CARD_SERVICES_INFO:
+	ret = CardServices(GetCardServicesInfo, &buf.servinfo);
+	break;
+    case DS_GET_CONFIGURATION_INFO:
+	ret = CardServices(GetConfigurationInfo, s->handle, &buf.config);
+	break;
+    case DS_GET_FIRST_TUPLE:
+	ret = CardServices(GetFirstTuple, s->handle, &buf.tuple);
+	break;
+    case DS_GET_NEXT_TUPLE:
+	ret = CardServices(GetNextTuple, s->handle, &buf.tuple);
+	break;
+    case DS_GET_TUPLE_DATA:
+	buf.tuple.TupleData = buf.tuple_parse.data;
+	buf.tuple.TupleDataMax = sizeof(buf.tuple_parse.data);
+	ret = CardServices(GetTupleData, s->handle, &buf.tuple);
+	break;
+    case DS_PARSE_TUPLE:
+	buf.tuple.TupleData = buf.tuple_parse.data;
+	ret = CardServices(ParseTuple, s->handle, &buf.tuple,
+			   &buf.tuple_parse.parse);
+	break;
+    case DS_RESET_CARD:
+	ret = CardServices(ResetCard, s->handle, NULL);
+	break;
+    case DS_GET_STATUS:
+	ret = CardServices(GetStatus, s->handle, &buf.status);
+	break;
+    case DS_VALIDATE_CIS:
+	ret = CardServices(ValidateCIS, s->handle, &buf.cisinfo);
+	break;
+    case DS_SUSPEND_CARD:
+	ret = CardServices(SuspendCard, s->handle, NULL);
+	break;
+    case DS_RESUME_CARD:
+	ret = CardServices(ResumeCard, s->handle, NULL);
+	break;
+    case DS_EJECT_CARD:
+	ret = CardServices(EjectCard, s->handle, NULL);
+	break;
+    case DS_INSERT_CARD:
+	ret = CardServices(InsertCard, s->handle, NULL);
+	break;
+    case DS_ACCESS_CONFIGURATION_REGISTER:
+	if ((buf.conf_reg.Action == CS_WRITE) && !suser())
+	    return -EPERM;
+	ret = CardServices(AccessConfigurationRegister, s->handle,
+			   &buf.conf_reg);
+	break;
+    case DS_GET_FIRST_REGION:
+        ret = CardServices(GetFirstRegion, s->handle, &buf.region);
+	break;
+    case DS_GET_NEXT_REGION:
+	ret = CardServices(GetNextRegion, s->handle, &buf.region);
+	break;
+    case DS_GET_FIRST_WINDOW:
+	buf.win_info.handle = (window_handle_t)s->handle;
+	ret = CardServices(GetFirstWindow, &buf.win_info.handle,
+			   &buf.win_info.window);
+	break;
+    case DS_GET_NEXT_WINDOW:
+	ret = CardServices(GetNextWindow, &buf.win_info.handle,
+			   &buf.win_info.window);
+	break;
+    case DS_GET_MEM_PAGE:
+	ret = CardServices(GetMemPage, buf.win_info.handle,
+			   &buf.win_info.map);
+	break;
+    case DS_REPLACE_CIS:
+	ret = CardServices(ReplaceCIS, s->handle, &buf.cisdump);
+	break;
+    case DS_BIND_REQUEST:
+	if (!suser()) return -EPERM;
+	err = bind_request(i, &buf.bind_info);
+	break;
+    case DS_GET_DEVICE_INFO:
+	err = get_device_info(i, &buf.bind_info, 1);
+	break;
+    case DS_GET_NEXT_DEVICE:
+	err = get_device_info(i, &buf.bind_info, 0);
+	break;
+    case DS_UNBIND_REQUEST:
+	err = unbind_request(i, &buf.bind_info);
+	break;
+    case DS_BIND_MTD:
+	if (!suser()) return -EPERM;
+	err = bind_mtd(i, &buf.mtd_info);
+	break;
+    default:
+	err = -EINVAL;
+    }
+    
+    if ((err == 0) && (ret != CS_SUCCESS)) {
+	DEBUG(2, "ds_ioctl: ret = %d\n", ret);
+	switch (ret) {
+	case CS_BAD_SOCKET: case CS_NO_CARD:
+	    err = -ENODEV; break;
+	case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
+	case CS_BAD_TUPLE:
+	    err = -EINVAL; break;
+	case CS_IN_USE:
+	    err = -EBUSY; break;
+	case CS_OUT_OF_RESOURCE:
+	    err = -ENOSPC; break;
+	case CS_NO_MORE_ITEMS:
+	    err = -ENODATA; break;
+	case CS_UNSUPPORTED_FUNCTION:
+	    err = -ENOSYS; break;
+	default:
+	    err = -EIO; break;
+	}
+    }
+    
+    if (cmd & IOC_OUT) copy_to_user((char *)arg, (char *)&buf, size);
+     
+    return err;
+} /* ds_ioctl */
+
+/*====================================================================*/
+
+static struct file_operations ds_fops = {
+    NULL,		/* lseek */
+    ds_read,		/* read */
+    ds_write,		/* write */
+    NULL,		/* readdir */
+    ds_poll,		/* poll */
+    ds_ioctl,		/* ioctl */
+    NULL,		/* mmap */
+    ds_open,		/* open */
+    NULL,		/* flush */
+    ds_release,		/* release */
+    NULL		/* fsync */
+};
+
+EXPORT_SYMBOL(register_pccard_driver);
+EXPORT_SYMBOL(unregister_pccard_driver);
+
+/*====================================================================*/
+
+int pcmcia_ds_init(void)
+{
+    client_reg_t client_reg;
+    servinfo_t serv;
+    bind_req_t bind;
+    socket_info_t *s;
+    int i, ret;
+    
+    DEBUG(0, "%s\n", version);
+    
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ds: Card Services release does not match!\n");
+	return -1;
+    }
+    if (serv.Count == 0) {
+	printk(KERN_NOTICE "ds: no socket drivers loaded!\n");
+	return -1;
+    }
+    
+    sockets = serv.Count;
+    socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL);
+    for (i = 0, s = socket_table; i < sockets; i++, s++) {
+	s->state = 0;
+	s->user = NULL;
+	s->req_pending = 0;
+	init_waitqueue_head(&s->queue);
+	init_waitqueue_head(&s->request);
+	s->handle = NULL;
+	s->removal.prev = s->removal.next = NULL;
+	s->removal.data = i;
+	s->removal.function = &handle_removal;
+	s->bind = NULL;
+    }
+    
+    /* Set up hotline to Card Services */
+    client_reg.dev_info = bind.dev_info = &dev_info;
+    client_reg.Attributes = INFO_MASTER_CLIENT;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ds_event;
+    client_reg.Version = 0x0210;
+    for (i = 0; i < sockets; i++) {
+	bind.Socket = i;
+	bind.Function = BIND_FN_ALL;
+	ret = CardServices(BindDevice, &bind);
+	if (ret != CS_SUCCESS) {
+	    cs_error(NULL, BindDevice, ret);
+	    break;
+	}
+	client_reg.event_callback_args.client_data = &socket_table[i];
+	ret = CardServices(RegisterClient, &socket_table[i].handle,
+			   &client_reg);
+	if (ret != CS_SUCCESS) {
+	    cs_error(NULL, RegisterClient, ret);
+	    break;
+	}
+    }
+    
+    /* Set up character device for user mode clients */
+    i = register_chrdev(0, "pcmcia", &ds_fops);
+    if (i == -EBUSY)
+	printk(KERN_NOTICE "unable to find a free device # for "
+	       "Driver Services\n");
+    else
+	major_dev = i;
+    
+    return 0;
+}
+
+#ifdef MODULE
+
+static int init_module(void)
+{
+	return pcmcia_ds_init();
+}
+
+void cleanup_module(void)
+{
+    int i;
+    if (major_dev != -1)
+	unregister_chrdev(major_dev, "pcmcia");
+    for (i = 0; i < sockets; i++)
+	CardServices(DeregisterClient, socket_table[i].handle);
+    sockets = 0;
+    kfree(socket_table);
+}
+
+#endif
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/i82365.c linux/drivers/pcmcia/i82365.c
--- v2.3.16/linux/drivers/pcmcia/i82365.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/i82365.c	Tue Sep  7 11:50:40 1999
@@ -0,0 +1,2819 @@
+/*======================================================================
+
+    Device driver for Intel 82365 and compatible PC Card controllers,
+    and Yenta-compatible PCI-to-CardBus controllers.
+
+    i82365.c 1.251 1999/09/07 15:19:23
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+/* ISA-bus controllers */
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+#include "ricoh.h"
+#include "o2micro.h"
+
+/* PCI-bus controllers */
+#include "yenta.h"
+#include "ti113x.h"
+#include "smc34c90.h"
+#include "topic.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0)
+static const char *version =
+"i82365.c $Revision: 1.249 $ $Date: 1999/08/28 04:01:46 $ (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+static void irq_count(int, void *, struct pt_regs *);
+static inline int _check_irq(int irq, int flags)
+{
+    if (request_irq(irq, irq_count, flags, "x", NULL) == 0) {
+	free_irq(irq, NULL);
+	return 0;
+    }
+    return -1;
+}
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#ifdef CONFIG_ISA
+/* Default base address for i82365sl and other ISA chips */
+static int i365_base = 0x3e0;
+/* Should we probe at 0x3e2 for an extra ISA controller? */
+static int extra_sockets = 0;
+/* Specify a socket number to ignore */
+static int ignore = -1;
+/* Bit map or list of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16] = { -1 };
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+#endif
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+/* External clock time, in nanoseconds.  120 ns = 8.33 MHz */
+static int cycle_time = 120;
+
+/* Cirrus options */
+static int has_dma = -1;
+static int has_led = -1;
+static int has_ring = -1;
+static int dynamic_mode = 0;
+static int freq_bypass = -1;
+static int setup_time = -1;
+static int cmd_time = -1;
+static int recov_time = -1;
+
+#ifdef CONFIG_ISA
+/* Vadem options */
+static int async_clock = -1;
+static int cable_mode = -1;
+static int wakeup = 0;
+#endif
+
+#ifdef CONFIG_ISA
+MODULE_PARM(i365_base, "i");
+MODULE_PARM(ignore, "i");
+MODULE_PARM(extra_sockets, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-16i");
+MODULE_PARM(cs_irq, "i");
+MODULE_PARM(async_clock, "i");
+MODULE_PARM(cable_mode, "i");
+MODULE_PARM(wakeup, "i");
+#endif
+
+MODULE_PARM(do_scan, "i");
+MODULE_PARM(poll_interval, "i");
+MODULE_PARM(cycle_time, "i");
+MODULE_PARM(has_dma, "i");
+MODULE_PARM(has_led, "i");
+MODULE_PARM(has_ring, "i");
+MODULE_PARM(dynamic_mode, "i");
+MODULE_PARM(freq_bypass, "i");
+MODULE_PARM(setup_time, "i");
+MODULE_PARM(cmd_time, "i");
+MODULE_PARM(recov_time, "i");
+
+#ifdef CONFIG_PCI
+/* Scan PCI bus? */
+static int do_pci_probe = 1;
+/* Default memory base address for CardBus controllers */
+static u_int cb_mem_base[] = { 0x68000000, 0xf8000000 };
+static int fast_pci = -1;
+static int hold_time = -1;
+/* Override BIOS interrupt routing mode? */
+static int irq_mode = -1;
+static int has_clkrun = -1;
+static int clkrun_sel = -1;
+static int pci_latency = -1;
+static int cb_latency = -1;
+static int cb_bus_base = 0;
+static int cb_bus_step = 2;
+static int cb_write_post = -1;
+MODULE_PARM(do_pci_probe, "i");
+MODULE_PARM(cb_mem_base, "i");
+MODULE_PARM(fast_pci, "i");
+MODULE_PARM(hold_time, "i");
+MODULE_PARM(irq_mode, "i");
+MODULE_PARM(has_clkrun, "i");
+MODULE_PARM(clkrun_sel, "i");
+MODULE_PARM(pci_latency, "i");
+MODULE_PARM(cb_latency, "i");
+MODULE_PARM(cb_bus_base, "i");
+MODULE_PARM(cb_bus_step, "i");
+MODULE_PARM(cb_write_post, "i");
+#endif
+
+#ifdef CONFIG_ISA
+#ifdef CONFIG_PCI
+/* PCI card status change interrupts? */
+static int pci_csc = 0;
+/* PCI IO card functional interrupts? */
+static int pci_int = 0;
+MODULE_PARM(pci_csc, "i");
+MODULE_PARM(pci_int, "i");
+#else /* no PCI */
+#define pci_csc		0
+#define pci_int		0
+#endif
+#else /* no ISA */
+#ifdef CONFIG_PCI
+#define pci_csc		0
+#define pci_int		1
+#else
+#error "No bus architectures defined!"
+#endif
+#endif
+
+/*====================================================================*/
+
+typedef struct cirrus_state_t {
+    u_char		misc1, misc2;
+    u_char		timer[6];
+} cirrus_state_t;
+
+typedef struct vg46x_state_t {
+    u_char		ctl, ema;
+} vg46x_state_t;
+
+typedef struct ti113x_state_t {
+    u_int		sysctl;
+    u_char		cardctl, devctl, diag;
+} ti113x_state_t;
+
+typedef struct rl5c4xx_state_t {
+    u_short		misc, ctl, io, mem;
+} rl5c4xx_state_t;
+
+typedef struct o2micro_state_t {
+    u_char		mode_a, mode_b, mode_c, mode_d;
+    u_char		mhpg, fifo, mode_e;
+} o2micro_state_t;
+
+typedef struct topic_state_t {
+    u_char		slot, ccr, cdr;
+    u_int		rcr;
+} topic_state_t;
+
+typedef struct socket_info_t {
+    u_short		type, flags;
+    socket_cap_t	cap;
+    u_short		ioaddr;
+    u_short		psock;
+    u_char		cs_irq, intr;
+    void		(*handler)(void *info, u_int events);
+    void		*info;
+#ifdef CONFIG_PROC_FS
+    struct proc_dir_entry *proc;
+#endif
+#ifdef CONFIG_PCI
+    u_short		vendor, device;
+    u_char		revision, bus, devfn;
+    u_short		bcr;
+    u_char		pci_lat, cb_lat, sub_bus;
+    u_char		cache, pmcs;
+    u_int		cb_phys;
+    char		*cb_virt;
+#endif
+    union {
+	cirrus_state_t		cirrus;
+	vg46x_state_t		vg46x;
+#ifdef CONFIG_PCI
+	o2micro_state_t		o2micro;
+	ti113x_state_t		ti113x;
+	rl5c4xx_state_t		rl5c4xx;
+	topic_state_t		topic;
+#endif
+    } state;
+} socket_info_t;
+
+/* Where we keep track of our sockets... */
+static int sockets = 0;
+static socket_info_t socket[8] = {
+    { 0, }, /* ... */
+};
+
+/* Default ISA interrupt mask */
+#define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
+
+static void pcic_interrupt_wrapper(u_long);
+static void pcic_interrupt(int irq, void *dev,
+				    struct pt_regs *regs);
+static int pcic_service(u_int sock, u_int cmd, void *arg);
+#ifdef CONFIG_PROC_FS
+static void pcic_proc_remove(u_short sock);
+#endif
+
+#ifdef CONFIG_ISA
+static int grab_irq;
+static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+#endif
+static struct timer_list poll_timer;
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL		0x8086
+#endif
+#ifndef PCI_VENDOR_ID_OMEGA
+#define PCI_VENDOR_ID_OMEGA		0x119b
+#endif
+#ifndef PCI_DEVICE_ID_OMEGA_PCMCIA
+#define PCI_DEVICE_ID_OMEGA_PCMCIA	0x1221
+#endif
+
+/* Default settings for PCI command configuration register */
+#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \
+		  PCI_COMMAND_MASTER|PCI_COMMAND_WAIT)
+
+#endif
+
+/* These definitions must match the pcic table! */
+typedef enum pcic_id {
+#ifdef CONFIG_ISA
+    IS_I82365A, IS_I82365B, IS_I82365DF,
+    IS_IBM, IS_RF5Cx96, IS_VLSI, IS_VG468, IS_VG469,
+    IS_PD6710, IS_PD672X, IS_VT83C469,
+#endif
+#ifdef CONFIG_PCI
+    IS_PD6729, IS_PD6730, IS_OZ6729, IS_OZ6730,
+    IS_I82092AA, IS_OM82C092G,
+    IS_PD6832, IS_OZ6832, IS_OZ6836,
+    IS_RL5C465, IS_RL5C466, IS_RL5C475, IS_RL5C476, IS_RL5C478,
+    IS_SMC34C90,
+    IS_TI1130, IS_TI1131, IS_TI1250A, IS_TI1220, IS_TI1221, IS_TI1210,
+    IS_TI1251A, IS_TI1251B, IS_TI1450, IS_TI1225, IS_TI1211, IS_TI1420,
+    IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97,
+    IS_UNK_PCI, IS_UNK_CARDBUS
+#endif
+} pcic_id;
+
+/* Flags for classifying groups of controllers */
+#define IS_VADEM	0x0001
+#define IS_CIRRUS	0x0002
+#define IS_TI		0x0004
+#define IS_O2MICRO	0x0008
+#define IS_VIA		0x0010
+#define IS_TOPIC	0x0020
+#define IS_RICOH	0x0040
+#define IS_UNKNOWN	0x0400
+#define IS_VG_PWR	0x0800
+#define IS_DF_PWR	0x1000
+#define IS_PCI		0x2000
+#define IS_CARDBUS	0x4000
+#define IS_ALIVE	0x8000
+
+typedef struct pcic_t {
+    char		*name;
+    u_short		flags;
+#ifdef CONFIG_PCI
+    u_short		vendor, device;
+#endif
+} pcic_t;
+
+static pcic_t pcic[] = {
+#ifdef CONFIG_ISA
+    { "Intel i82365sl A step", 0 },
+    { "Intel i82365sl B step", 0 },
+    { "Intel i82365sl DF", IS_DF_PWR },
+    { "IBM Clone", 0 },
+    { "Ricoh RF5C296/396", 0 },
+    { "VLSI 82C146", 0 },
+    { "Vadem VG-468", IS_VADEM },
+    { "Vadem VG-469", IS_VADEM|IS_VG_PWR },
+    { "Cirrus PD6710", IS_CIRRUS },
+    { "Cirrus PD672x", IS_CIRRUS },
+    { "VIA VT83C469", IS_CIRRUS|IS_VIA },
+#endif
+#ifdef CONFIG_PCI
+    { "Cirrus PD6729", IS_CIRRUS|IS_PCI,
+      PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6729 },
+    { "Cirrus PD6730", IS_CIRRUS|IS_PCI,
+      PCI_VENDOR_ID_CIRRUS, 0xffff },
+    { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6729 },
+    { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6730 },
+    { "Intel 82092AA", IS_PCI,
+      PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_OMEGA_PCMCIA },
+    { "Omega Micro 82C092G", IS_PCI,
+      PCI_VENDOR_ID_OMEGA, PCI_DEVICE_ID_OMEGA_PCMCIA },
+    { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS,
+      PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832 },
+    { "O2Micro OZ6832/OZ6833", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6832 },
+    { "O2Micro OZ6836/OZ6860", IS_O2MICRO|IS_CARDBUS|IS_VG_PWR,
+      PCI_VENDOR_ID_O2, PCI_DEVICE_ID_O2_6836 },
+    { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465 },
+    { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466 },
+    { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475 },
+    { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476 },
+    { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478 },
+    { "SMC 34C90", IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_SMC, PCI_DEVICE_ID_SMC_34C90 },
+    { "TI 1130", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130 },
+    { "TI 1131", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1131 },
+    { "TI 1250A", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1250A },
+    { "TI 1220", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1220 },
+    { "TI 1221", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1221 },
+    { "TI 1210", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210 },
+    { "TI 1251A", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251A },
+    { "TI 1251B", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1251B },
+    { "TI 1450", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1450 },
+    { "TI 1225", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1225 },
+    { "TI 1211", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211 },
+    { "TI 1420", IS_TI|IS_CARDBUS|IS_DF_PWR,
+      PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1420 },
+    { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+      PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_A },
+    { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+      PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95_B },
+    { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC|IS_DF_PWR,
+      PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97 },
+    { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 },
+    { "Unknown", IS_CARDBUS|IS_DF_PWR|IS_UNKNOWN, 0, 0 }
+#endif
+};
+
+#define PCIC_COUNT	(sizeof(pcic)/sizeof(pcic_t))
+
+/*====================================================================*/
+
+/* Some PCI shortcuts */
+
+#ifdef CONFIG_PCI
+
+#define pci_readb		pcibios_read_config_byte
+#define pci_writeb		pcibios_write_config_byte
+#define pci_readw		pcibios_read_config_word
+#define pci_writew		pcibios_write_config_word
+#define pci_readl		pcibios_read_config_dword
+#define pci_writel		pcibios_write_config_dword
+
+#define cb_readb(s, r)		readb(socket[s].cb_virt + (r))
+#define cb_readl(s, r)		readl(socket[s].cb_virt + (r))
+#define cb_writeb(s, r, v)	writeb(v, socket[s].cb_virt + (r))
+#define cb_writel(s, r, v)	writel(v, socket[s].cb_virt + (r))
+
+static void cb_get_power(u_short sock, socket_state_t *state);
+static void cb_set_power(u_short sock, socket_state_t *state);
+#endif
+
+/*====================================================================*/
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+#ifdef CONFIG_PCI
+    if (socket[sock].cb_virt)
+	return cb_readb(sock, 0x0800 + reg);
+    else
+#endif
+    {
+	u_short port = socket[sock].ioaddr;
+	u_char val;
+	reg = I365_REG(socket[sock].psock, reg);
+	outb(reg, port); val = inb(port+1);
+	return val;
+    }
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+#ifdef CONFIG_PCI
+    if (socket[sock].cb_virt)
+	cb_writeb(sock, 0x0800 + reg, data);
+    else
+#endif
+    {
+	u_short port = socket[sock].ioaddr;
+	u_char val = I365_REG(socket[sock].psock, reg);
+	outb(val, port); outb(data, port+1);
+    }
+}
+
+static void i365_bset(u_short sock, u_short reg, u_char mask)
+{
+    u_char d = i365_get(sock, reg);
+    d |= mask;
+    i365_set(sock, reg, d);
+}
+
+static void i365_bclr(u_short sock, u_short reg, u_char mask)
+{
+    u_char d = i365_get(sock, reg);
+    d &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+static void i365_bflip(u_short sock, u_short reg, u_char mask, int b)
+{
+    u_char d = i365_get(sock, reg);
+    if (b)
+	d |= mask;
+    else
+	d &= ~mask;
+    i365_set(sock, reg, d);
+}
+
+static u_short i365_get_pair(u_short sock, u_short reg)
+{
+    u_short a, b;
+    a = i365_get(sock, reg);
+    b = i365_get(sock, reg+1);
+    return (a + (b<<8));
+}
+
+static void i365_set_pair(u_short sock, u_short reg, u_short data)
+{
+    i365_set(sock, reg, data & 0xff);
+    i365_set(sock, reg+1, data >> 8);
+}
+
+/*======================================================================
+
+    Code to save and restore global state information for Cirrus
+    PD67xx controllers, and to set and report global configuration
+    options.
+
+    The VIA controllers also use these routines, as they are mostly
+    Cirrus lookalikes, without the timing registers.
+    
+======================================================================*/
+
+#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
+
+static void cirrus_get_state(u_short s)
+{
+    int i;
+    cirrus_state_t *p = &socket[s].state.cirrus;
+    p->misc1 = i365_get(s, PD67_MISC_CTL_1);
+    p->misc1 &= (PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+    p->misc2 = i365_get(s, PD67_MISC_CTL_2);
+    for (i = 0; i < 6; i++)
+	p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
+}
+
+static void cirrus_set_state(u_short s)
+{
+    int i;
+    u_char misc;
+    cirrus_state_t *p = &socket[s].state.cirrus;
+
+    misc = i365_get(s, PD67_MISC_CTL_2);
+    i365_set(s, PD67_MISC_CTL_2, p->misc2);
+    if (misc & PD67_MC2_SUSPEND) mdelay(50);
+    misc = i365_get(s, PD67_MISC_CTL_1);
+    misc &= ~(PD67_MC1_MEDIA_ENA | PD67_MC1_INPACK_ENA);
+    i365_set(s, PD67_MISC_CTL_1, misc | p->misc1);
+    for (i = 0; i < 6; i++)
+	i365_set(s, PD67_TIME_SETUP(0)+i, p->timer[i]);
+}
+
+#ifdef CONFIG_PCI
+static int cirrus_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    flip(socket[s].bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc);
+    return 0;
+}
+#endif /* CONFIG_PCI */
+
+static u_int cirrus_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    cirrus_state_t *p = &socket[s].state.cirrus;
+    u_int mask = 0xffff;
+
+    if (has_ring == -1) has_ring = 1;
+    flip(p->misc2, PD67_MC2_IRQ15_RI, has_ring);
+    flip(p->misc2, PD67_MC2_DYNAMIC_MODE, dynamic_mode);
+    if (p->misc2 & PD67_MC2_IRQ15_RI)
+	strcat(buf, " [ring]");
+    if (p->misc2 & PD67_MC2_DYNAMIC_MODE)
+	strcat(buf, " [dyn mode]");
+    if (p->misc1 & PD67_MC1_INPACK_ENA)
+	strcat(buf, " [inpack]");
+    if (!(t->flags & (IS_PCI | IS_CARDBUS))) {
+	if (p->misc2 & PD67_MC2_IRQ15_RI)
+	    mask &= ~0x8000;
+	if (has_led > 0) {
+	    strcat(buf, " [led]");
+	    mask &= ~0x1000;
+	}
+	if (has_dma > 0) {
+	    strcat(buf, " [dma]");
+	    mask &= ~0x0600;
+	flip(p->misc2, PD67_MC2_FREQ_BYPASS, freq_bypass);
+	if (p->misc2 & PD67_MC2_FREQ_BYPASS)
+	    strcat(buf, " [freq bypass]");
+	}
+#ifdef CONFIG_PCI
+    } else {
+	p->misc1 &= ~PD67_MC1_MEDIA_ENA;
+	flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci);
+	if (p->misc2 & PD67_MC2_IRQ15_RI)
+	    mask &= (socket[s].type == IS_PD6730) ? ~0x0400 : ~0x8000;
+#endif
+    }
+    if (!(t->flags & IS_VIA)) {
+	if (setup_time >= 0)
+	    p->timer[0] = p->timer[3] = setup_time;
+	if (cmd_time > 0) {
+	    p->timer[1] = cmd_time;
+	    p->timer[4] = cmd_time*2+4;
+	}
+	if (p->timer[1] == 0) {
+	    p->timer[1] = 6; p->timer[4] = 16;
+	    if (p->timer[0] == 0)
+		p->timer[0] = p->timer[3] = 1;
+	}
+	if (recov_time >= 0)
+	    p->timer[2] = p->timer[5] = recov_time;
+	buf += strlen(buf);
+	sprintf(buf, " [%d/%d/%d] [%d/%d/%d]", p->timer[0], p->timer[1],
+		p->timer[2], p->timer[3], p->timer[4], p->timer[5]);
+    }
+    return mask;
+}
+
+/*======================================================================
+
+    Code to save and restore global state information for Vadem VG468
+    and VG469 controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void vg46x_get_state(u_short s)
+{
+    vg46x_state_t *p = &socket[s].state.vg46x;
+    p->ctl = i365_get(s, VG468_CTL);
+    if (socket[s].type == IS_VG469)
+	p->ema = i365_get(s, VG469_EXT_MODE);
+}
+
+static void vg46x_set_state(u_short s)
+{
+    vg46x_state_t *p = &socket[s].state.vg46x;
+    i365_set(s, VG468_CTL, p->ctl);
+    if (socket[s].type == IS_VG469)
+	i365_set(s, VG469_EXT_MODE, p->ema);
+}
+
+static u_int vg46x_set_opts(u_short s, char *buf)
+{
+    vg46x_state_t *p = &socket[s].state.vg46x;
+    
+    flip(p->ctl, VG468_CTL_ASYNC, async_clock);
+    flip(p->ema, VG469_MODE_CABLE, cable_mode);
+    if (p->ctl & VG468_CTL_ASYNC)
+	strcat(buf, " [async]");
+    if (p->ctl & VG468_CTL_INPACK)
+	strcat(buf, " [inpack]");
+    if (socket[s].type == IS_VG469) {
+	u_char vsel = i365_get(s, VG469_VSELECT);
+	if (vsel & VG469_VSEL_EXT_STAT) {
+	    strcat(buf, " [ext mode]");
+	    if (vsel & VG469_VSEL_EXT_BUS)
+		strcat(buf, " [isa buf]");
+	}
+	if (p->ema & VG469_MODE_CABLE)
+	    strcat(buf, " [cable]");
+	if (p->ema & VG469_MODE_COMPAT)
+	    strcat(buf, " [c step]");
+    }
+    return 0xffff;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for TI 1130 and
+    TI 1131 controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void ti113x_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &socket[s].state.ti113x;
+    pci_readl(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, &p->sysctl);
+    pci_readb(t->bus, t->devfn, TI113X_CARD_CONTROL, &p->cardctl);
+    pci_readb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, &p->devctl);
+    pci_readb(t->bus, t->devfn, TI1250_DIAGNOSTIC, &p->diag);
+}
+
+static void ti113x_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &socket[s].state.ti113x;
+    pci_writel(t->bus, t->devfn, TI113X_SYSTEM_CONTROL, p->sysctl);
+    pci_writeb(t->bus, t->devfn, TI113X_CARD_CONTROL, p->cardctl);
+    pci_writeb(t->bus, t->devfn, TI113X_DEVICE_CONTROL, p->devctl);
+    pci_writeb(t->bus, t->devfn, TI1250_MULTIMEDIA_CTL, 0);
+    pci_writeb(t->bus, t->devfn, TI1250_DIAGNOSTIC, p->diag);
+    i365_set_pair(s, TI113X_IO_OFFSET(0), 0);
+    i365_set_pair(s, TI113X_IO_OFFSET(1), 0);
+}
+
+static int ti113x_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &t->state.ti113x;
+    t->intr = (pcsc) ? I365_INTR_ENA : 0;
+    if (t->type <= IS_TI1131) {
+	p->cardctl &= ~(TI113X_CCR_PCI_IRQ_ENA |
+			TI113X_CCR_PCI_IREQ | TI113X_CCR_PCI_CSC);
+	if (pcsc)
+	    p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC;
+	if (pint)
+	    p->cardctl |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_IREQ;
+    } else if (t->type == IS_TI1250A) {
+	p->diag &= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
+	if (pcsc)
+	    p->diag |= TI1250_DIAG_PCI_CSC;
+	if (pint)
+	    p->diag |= TI1250_DIAG_PCI_IREQ;
+    }
+    return 0;
+}
+
+static u_int ti113x_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    ti113x_state_t *p = &t->state.ti113x;
+    u_int mask = 0xffff;
+    int old = (t->type <= IS_TI1131);
+    
+    flip(p->sysctl, TI113X_SCR_CLKRUN_ENA, has_clkrun);
+    flip(p->sysctl, TI113X_SCR_CLKRUN_SEL, clkrun_sel);
+    flip(p->cardctl, TI113X_CCR_RIENB, has_ring);
+    p->cardctl &= ~TI113X_CCR_ZVENABLE;
+    switch (irq_mode) {
+    case 1:
+	p->devctl &= ~TI113X_DCR_IMODE_MASK;
+	p->devctl |= TI113X_DCR_IMODE_ISA;
+	break;
+    case 2:
+	p->devctl &= ~TI113X_DCR_IMODE_MASK;
+	p->devctl |= TI113X_DCR_IMODE_SERIAL;
+	break;
+    case 3:
+	p->devctl &= ~TI113X_DCR_IMODE_MASK;
+	p->devctl |= TI12XX_DCR_IMODE_ALL_SERIAL;
+	break;
+    default:
+	if ((p->devctl & TI113X_DCR_IMODE_MASK) == 0)
+	    p->devctl |= TI113X_DCR_IMODE_ISA;
+    }
+    if (p->cardctl & TI113X_CCR_RIENB) {
+	strcat(buf, " [ring]");
+	if (old) mask &= ~0x8000;
+    }
+    if (old && (p->sysctl & TI113X_SCR_CLKRUN_ENA)) {
+	if (p->sysctl & TI113X_SCR_CLKRUN_SEL) {
+	    strcat(buf, " [clkrun irq 12]");
+	    mask &= ~0x1000;
+	} else {
+	    strcat(buf, " [clkrun irq 10]");
+	    mask &= ~0x0400;
+	}
+    }
+    if (p->sysctl & TI113X_SCR_PWRSAVINGS)
+	strcat(buf, " [pwr save]");
+    switch (p->devctl & TI113X_DCR_IMODE_MASK) {
+    case TI12XX_DCR_IMODE_PCI_ONLY:
+	strcat(buf, " [pci only]");
+	mask = 0;
+	break;
+    case TI113X_DCR_IMODE_ISA:
+	strcat(buf, " [isa irq]");
+	if (old) mask &= ~0x0018;
+	break;
+    case TI113X_DCR_IMODE_SERIAL:
+	strcat(buf, " [pci + serial irq]");
+	mask = 0xffff;
+	break;
+    case TI12XX_DCR_IMODE_ALL_SERIAL:
+	strcat(buf, " [serial pci & irq]");
+	mask = 0xffff;
+	break;
+    }
+    return mask;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for the Ricoh
+    RL5C4XX controllers, and to set and report global configuration
+    options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void rl5c4xx_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+    pci_readw(t->bus, t->devfn, RL5C4XX_MISC, &p->misc);
+    pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_CTL, &p->ctl);
+    pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, &p->io);
+    pci_readw(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, &p->mem);
+}
+
+static void rl5c4xx_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+    pci_writew(t->bus, t->devfn, RL5C4XX_MISC, p->misc);
+    pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_CTL, p->ctl);
+    pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_IO_0, p->io);
+    pci_writew(t->bus, t->devfn, RL5C4XX_16BIT_MEM_0, p->mem);
+}
+
+static u_int rl5c4xx_set_opts(u_short s, char *buf)
+{
+    rl5c4xx_state_t *p = &socket[s].state.rl5c4xx;
+    u_int mask = 0xffff;
+    int old = (socket[s].type < IS_RL5C475);
+
+    p->ctl = RL5C4XX_16CTL_IO_TIMING | RL5C4XX_16CTL_MEM_TIMING;
+    if (old) p->ctl |= RL5C46X_16CTL_LEVEL_1 | RL5C46X_16CTL_LEVEL_2;
+    
+    if (setup_time >= 0) {
+	p->io = (p->io & ~RL5C4XX_SETUP_MASK) +
+	    ((setup_time+1) << RL5C4XX_SETUP_SHIFT);
+	p->mem = (p->mem & ~RL5C4XX_SETUP_MASK) +
+	    (setup_time << RL5C4XX_SETUP_SHIFT);
+    }
+    if (cmd_time >= 0) {
+	p->io = (p->io & ~RL5C4XX_CMD_MASK) +
+	    (cmd_time << RL5C4XX_CMD_SHIFT);
+	p->mem = (p->mem & ~RL5C4XX_CMD_MASK) +
+	    (cmd_time << RL5C4XX_CMD_SHIFT);
+    }
+    if (hold_time >= 0) {
+	p->io = (p->io & ~RL5C4XX_HOLD_MASK) +
+	    (hold_time << RL5C4XX_HOLD_SHIFT);
+	p->mem = (p->mem & ~RL5C4XX_HOLD_MASK) +
+	    (hold_time << RL5C4XX_HOLD_SHIFT);
+    }
+    if (!old) {
+	switch (irq_mode) {
+	case 1:
+	    p->misc &= ~RL5C47X_MISC_SRIRQ_ENA; break;
+	case 2:
+	    p->misc |= RL5C47X_MISC_SRIRQ_ENA; break;
+	}
+	if (p->misc & RL5C47X_MISC_SRIRQ_ENA)
+	    sprintf(buf, " [serial irq]");
+	else
+	    sprintf(buf, " [isa irq]");
+	buf += strlen(buf);
+    }
+    sprintf(buf, " [io %d/%d/%d] [mem %d/%d/%d]",
+	    (p->io & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT,
+	    (p->io & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT,
+	    (p->io & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT,
+	    (p->mem & RL5C4XX_SETUP_MASK) >> RL5C4XX_SETUP_SHIFT,
+	    (p->mem & RL5C4XX_CMD_MASK) >> RL5C4XX_CMD_SHIFT,
+	    (p->mem & RL5C4XX_HOLD_MASK) >> RL5C4XX_HOLD_SHIFT);
+    return mask;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for O2Micro
+    controllers, and to set and report global configuration options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void o2micro_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    o2micro_state_t *p = &socket[s].state.o2micro;
+    if ((t->revision == 0x34) || (t->revision == 0x62)) {
+	p->mode_a = i365_get(s, O2_MODE_A_2);
+	p->mode_b = i365_get(s, O2_MODE_B_2);
+    } else {
+	p->mode_a = i365_get(s, O2_MODE_A);
+	p->mode_b = i365_get(s, O2_MODE_B);
+    }
+    p->mode_c = i365_get(s, O2_MODE_C);
+    p->mode_d = i365_get(s, O2_MODE_D);
+    if (t->flags & IS_CARDBUS) {
+	p->mhpg = i365_get(s, O2_MHPG_DMA);
+	p->fifo = i365_get(s, O2_FIFO_ENA);
+	p->mode_e = i365_get(s, O2_MODE_E);
+    }
+}
+
+static void o2micro_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    o2micro_state_t *p = &socket[s].state.o2micro;
+    if ((t->revision == 0x34) || (t->revision == 0x62)) {
+	i365_set(s, O2_MODE_A_2, p->mode_a);
+	i365_set(s, O2_MODE_B_2, p->mode_b);
+    } else {
+	i365_set(s, O2_MODE_A, p->mode_a);
+	i365_set(s, O2_MODE_B, p->mode_b);
+    }
+    i365_set(s, O2_MODE_C, p->mode_c);
+    i365_set(s, O2_MODE_D, p->mode_d);
+    if (t->flags & IS_CARDBUS) {
+	i365_set(s, O2_MHPG_DMA, p->mhpg);
+	i365_set(s, O2_FIFO_ENA, p->fifo);
+	i365_set(s, O2_MODE_E, p->mode_e);
+    }
+}
+
+static u_int o2micro_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    o2micro_state_t *p = &socket[s].state.o2micro;
+    u_int mask = 0xffff;
+
+    p->mode_b = (p->mode_b & ~O2_MODE_B_IDENT) | O2_MODE_B_ID_CSTEP;
+    flip(p->mode_b, O2_MODE_B_IRQ15_RI, has_ring);
+    p->mode_c &= ~(O2_MODE_C_ZVIDEO | O2_MODE_C_DREQ_MASK);
+    if (t->flags & IS_CARDBUS) {
+	p->mode_d &= ~O2_MODE_D_W97_IRQ;
+	p->mode_e &= ~O2_MODE_E_MHPG_DMA;
+	p->mhpg |= O2_MHPG_CINT_ENA | O2_MHPG_CSC_ENA;
+	p->mhpg &= ~O2_MHPG_CHANNEL;
+    } else {
+	if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000;
+    }
+    sprintf(buf, " [a %02x] [b %02x] [c %02x] [d %02x]",
+	    p->mode_a, p->mode_b, p->mode_c, p->mode_d);
+    if (t->flags & IS_CARDBUS) {
+	buf += strlen(buf);
+	sprintf(buf, " [mhpg %02x] [fifo %02x] [e %02x]",
+		p->mhpg, p->fifo, p->mode_e);
+    }
+    return mask;
+}
+
+#endif
+
+/*======================================================================
+
+    Code to save and restore global state information for the Toshiba
+    ToPIC 95 and 97 controllers, and to set and report global
+    configuration options.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void topic_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    topic_state_t *p = &socket[s].state.topic;
+    pci_readb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, &p->slot);
+    pci_readb(t->bus, t->devfn, TOPIC_CARD_CONTROL, &p->ccr);
+    pci_readb(t->bus, t->devfn, TOPIC_CARD_DETECT, &p->cdr);
+    pci_readl(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, &p->rcr);
+}
+
+static void topic_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    topic_state_t *p = &socket[s].state.topic;
+    pci_writeb(t->bus, t->devfn, TOPIC_SLOT_CONTROL, p->slot);
+    pci_writeb(t->bus, t->devfn, TOPIC_CARD_CONTROL, p->ccr);
+    pci_writeb(t->bus, t->devfn, TOPIC_CARD_DETECT, p->cdr);
+    pci_writel(t->bus, t->devfn, TOPIC_REGISTER_CONTROL, p->rcr);
+}
+
+static int topic_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    if (socket[s].type == IS_TOPIC97) {
+	topic_state_t *p = &socket[s].state.topic;
+	flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc);
+	return 0;
+    } else {
+	return !pcsc;
+    }
+}
+
+static u_int topic_set_opts(u_short s, char *buf)
+{
+    topic_state_t *p = &socket[s].state.topic;
+
+    p->slot |= TOPIC_SLOT_SLOTON|TOPIC_SLOT_SLOTEN|TOPIC_SLOT_ID_LOCK;
+    p->cdr |= TOPIC_CDR_MODE_PC32;
+    p->cdr &= ~(TOPIC_CDR_SW_DETECT);
+    sprintf(buf, " [slot 0x%02x] [ccr 0x%02x] [cdr 0x%02x] [rcr 0x%02x]",
+	    p->slot, p->ccr, p->cdr, p->rcr);
+    return 0xffff;
+}
+
+#endif
+
+/*======================================================================
+
+    Routines to handle common CardBus options
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    
+    pci_readb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, &t->cache);
+    pci_readb(t->bus, t->devfn, PCI_LATENCY_TIMER, &t->pci_lat);
+    pci_readb(t->bus, t->devfn, CB_LATENCY_TIMER, &t->cb_lat);
+    pci_readb(t->bus, t->devfn, CB_CARDBUS_BUS, &t->cap.cardbus);
+    pci_readb(t->bus, t->devfn, CB_SUBORD_BUS, &t->sub_bus);
+    pci_readw(t->bus, t->devfn, CB_BRIDGE_CONTROL, &t->bcr);
+    {
+	struct pci_dev *pdev = pci_find_slot(t->bus, t->devfn);
+	t->cap.pci_irq = (pdev) ? pdev->irq : 0;
+    }
+    if (t->cap.pci_irq >= NR_IRQS) t->cap.pci_irq = 0;
+}
+
+static void cb_set_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    if (t->pmcs)
+	pci_writew(t->bus, t->devfn, t->pmcs, PCI_PMCS_PWR_STATE_D0);
+    pci_writel(t->bus, t->devfn, CB_LEGACY_MODE_BASE, 0);
+    pci_writel(t->bus, t->devfn, PCI_BASE_ADDRESS_0, t->cb_phys);
+    pci_writew(t->bus, t->devfn, PCI_COMMAND, CMD_DFLT);
+    pci_writeb(t->bus, t->devfn, PCI_CACHE_LINE_SIZE, t->cache);
+    pci_writeb(t->bus, t->devfn, PCI_LATENCY_TIMER, t->pci_lat);
+    pci_writeb(t->bus, t->devfn, CB_LATENCY_TIMER, t->cb_lat);
+    pci_writeb(t->bus, t->devfn, CB_CARDBUS_BUS, t->cap.cardbus);
+    pci_writeb(t->bus, t->devfn, CB_SUBORD_BUS, t->sub_bus);
+    pci_writew(t->bus, t->devfn, CB_BRIDGE_CONTROL, t->bcr);
+}
+
+static int cb_get_irq_mode(u_short s)
+{
+    return (!(socket[s].bcr & CB_BCR_ISA_IRQ));
+}
+
+static int cb_set_irq_mode(u_short s, int pcsc, int pint)
+{
+    socket_info_t *t = &socket[s];
+    flip(t->bcr, CB_BCR_ISA_IRQ, !(pint));
+    if (t->flags & IS_CIRRUS)
+	return cirrus_set_irq_mode(s, pcsc, pint);
+    else if (t->flags & IS_TI)
+	return ti113x_set_irq_mode(s, pcsc, pint);
+    else if (t->flags & IS_TOPIC)
+	return topic_set_irq_mode(s, pcsc, pint);
+    return 0;
+}
+
+static void pci_scan(u_short sock);
+
+static void cb_set_opts(u_short s, char *buf)
+{
+    socket_info_t *t = &socket[s];
+    t->bcr |= CB_BCR_WRITE_POST;
+    /* some TI1130's seem to exhibit problems with write posting */
+    if (((t->type == IS_TI1130) && (t->revision == 4) &&
+	 (cb_write_post < 0)) || (cb_write_post == 0))
+	t->bcr &= ~CB_BCR_WRITE_POST;
+    if (t->cache == 0) t->cache = 8;
+    if (pci_latency >= 0) t->pci_lat = pci_latency;
+    if (t->pci_lat == 0) t->pci_lat = 0xa8;
+    if (cb_latency >= 0) t->cb_lat = cb_latency;
+    if (t->cb_lat == 0) t->cb_lat = 0xb0;
+    if ((t->cap.pci_irq == 0) && (pci_csc || pci_int) && do_scan)
+	pci_scan(s);
+    if (t->cap.pci_irq == 0)
+	strcat(buf, " [no pci irq]");
+    else
+	sprintf(buf, " [pci irq %d]", t->cap.pci_irq);
+    buf += strlen(buf);
+    if ((cb_bus_base > 0) || (t->cap.cardbus == 0)) {
+	if (cb_bus_base <= 0) cb_bus_base = 0x20;
+	t->cap.cardbus = cb_bus_base;
+	t->sub_bus = cb_bus_base+cb_bus_step;
+	cb_bus_base += cb_bus_step+1;
+    }
+    if (!(t->flags & IS_TOPIC))
+	t->cap.features |= SS_CAP_PAGE_REGS;
+    sprintf(buf, " [lat %d/%d] [bus %d/%d]",
+	    t->pci_lat, t->cb_lat, t->cap.cardbus, t->sub_bus);
+}
+
+#endif
+
+/*======================================================================
+
+    Generic routines to get and set controller options
+    
+======================================================================*/
+
+static void get_host_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+    if (t->flags & IS_CIRRUS)
+	cirrus_get_state(s);
+#ifdef CONFIG_ISA
+    else if (t->flags & IS_VADEM)
+	vg46x_get_state(s);
+#endif
+#ifdef CONFIG_PCI
+    else if (t->flags & IS_O2MICRO)
+	o2micro_get_state(s);
+    else if (t->flags & IS_TI)
+	ti113x_get_state(s);
+    else if (t->flags & IS_RICOH)
+	rl5c4xx_get_state(s);
+    else if (t->flags & IS_TOPIC)
+	topic_get_state(s);
+    if (t->flags & IS_CARDBUS)
+	cb_get_state(s);
+#endif
+}
+
+static void set_host_state(u_short s)
+{
+    socket_info_t *t = &socket[s];
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS)
+	cb_set_state(s);
+#endif
+    if (t->flags & IS_CIRRUS)
+	cirrus_set_state(s);
+    else {
+	i365_set(s, I365_GBLCTL, 0x00);
+	i365_set(s, I365_GENCTL, 0x00);
+    }
+    i365_bflip(s, I365_INTCTL, I365_INTR_ENA, t->intr);
+#ifdef CONFIG_ISA
+    if (t->flags & IS_VADEM)
+	vg46x_set_state(s);
+#endif
+#ifdef CONFIG_PCI
+    if (t->flags & IS_O2MICRO)
+	o2micro_set_state(s);
+    else if (t->flags & IS_TI)
+	ti113x_set_state(s);
+    else if (t->flags & IS_RICOH)
+	rl5c4xx_set_state(s);
+    else if (t->flags & IS_TOPIC)
+	topic_set_state(s);
+#endif
+}
+
+static u_int set_host_opts(u_short s, u_short ns)
+{
+    u_short i;
+    u_int m = 0xffff;
+    char buf[128];
+
+    for (i = s; i < s+ns; i++) {
+	if (socket[i].flags & IS_ALIVE) {
+	    printk(KERN_INFO "    host opts [%d]: already alive!\n", i);
+	    continue;
+	}
+	buf[0] = '\0';
+	get_host_state(i);
+	if (socket[i].flags & IS_CIRRUS)
+	    m = cirrus_set_opts(i, buf);
+#ifdef CONFIG_ISA
+	else if (socket[i].flags & IS_VADEM)
+	    m = vg46x_set_opts(i, buf);
+#endif
+#ifdef CONFIG_PCI
+	else if (socket[i].flags & IS_O2MICRO)
+	    m = o2micro_set_opts(i, buf);
+	else if (socket[i].flags & IS_TI)
+	    m = ti113x_set_opts(i, buf);
+	else if (socket[i].flags & IS_RICOH)
+	    m = rl5c4xx_set_opts(i, buf);
+	else if (socket[i].flags & IS_TOPIC)
+	    m = topic_set_opts(i, buf);
+	if (socket[i].flags & IS_CARDBUS)
+	    cb_set_opts(i, buf+strlen(buf));
+#endif
+	set_host_state(i);
+	printk(KERN_INFO "    host opts [%d]:%s\n", i,
+	       (*buf) ? buf : " none");
+    }
+#ifdef CONFIG_PCI
+    /* Mask out all PCI interrupts */
+    for (i = 0; i < sockets; i++)
+	m &= ~(1<<socket[i].cap.pci_irq);
+    {
+	struct pci_dev *p;
+	for (p = pci_devices; p; p = p->next)
+	    m &= ~(1<<p->irq);
+    }
+#endif
+    return m;
+}
+
+/*======================================================================
+
+    Interrupt testing code, for ISA and PCI interrupts
+    
+======================================================================*/
+
+static volatile u_int irq_hits;
+static u_short irq_sock;
+
+static void irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+#ifdef CONFIG_PCI
+    if (socket[irq_sock].flags & IS_CARDBUS) {
+	cb_writel(irq_sock, CB_SOCKET_EVENT, -1);
+    } else
+#endif
+    i365_get(irq_sock, I365_CSC);
+    irq_hits++;
+    DEBUG(2, ("-> hit on irq %d\n", irq));
+}
+
+static u_int test_irq(u_short sock, int irq, int pci)
+{
+    u_char csc = (pci) ? 0 : irq;
+    DEBUG(2, "  testing %s irq %d\n", pci ? "PCI" : "ISA", irq);
+    
+    if (request_irq(irq, irq_count, (pci?SA_SHIRQ:0), "scan", NULL) != 0)
+	return 1;
+    irq_hits = 0; irq_sock = sock;
+    current->state = TASK_INTERRUPTIBLE;
+    schedule_timeout(HZ/100);
+    if (irq_hits) {
+	free_irq(irq, NULL);
+	DEBUG(2, ("    spurious hit!\n"));
+	return 1;
+    }
+
+    /* Generate one interrupt */
+#ifdef CONFIG_PCI
+    if (socket[sock].flags & IS_CARDBUS) {
+	cb_writel(sock, CB_SOCKET_EVENT, -1);
+	i365_set(sock, I365_CSCINT, I365_CSC_STSCHG | (csc << 4));
+	cb_writel(sock, CB_SOCKET_EVENT, -1);
+	cb_writel(sock, CB_SOCKET_MASK, CB_SM_CSTSCHG);
+	cb_writel(sock, CB_SOCKET_FORCE, CB_SE_CSTSCHG);
+	udelay(1000);
+	cb_writel(sock, CB_SOCKET_EVENT, -1);
+	cb_writel(sock, CB_SOCKET_MASK, 0);
+    } else
+#endif
+    {
+	i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (csc << 4));
+	i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
+	udelay(1000);
+    }
+
+    free_irq(irq, NULL);
+
+    /* mask all interrupts */
+    i365_set(sock, I365_CSCINT, 0);
+    DEBUG(2, "    hits = %d\n", irq_hits);
+    
+    return (irq_hits != 1);
+}
+
+#ifdef CONFIG_ISA
+
+static u_int isa_scan(u_short sock, u_int mask0)
+{
+    u_int mask1 = 0;
+    int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    /* Don't probe level-triggered interrupts -- reserved for PCI */
+    mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
+#endif
+    
+#ifdef CONFIG_PCI
+    /* Only scan if we can select ISA csc irq's */
+    if (!(socket[sock].flags & IS_CARDBUS) ||
+	(cb_set_irq_mode(sock, 0, 0) == 0))
+#endif
+    if (do_scan) {
+	set_host_state(sock);
+	i365_set(sock, I365_CSCINT, 0);
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (test_irq(sock, i, 0) == 0))
+		mask1 |= (1 << i);
+	for (i = 0; i < 16; i++)
+	    if ((mask1 & (1 << i)) && (test_irq(sock, i, 0) != 0))
+		mask1 ^= (1 << i);
+    }
+    
+    printk(KERN_INFO "    ISA irqs (");
+    if (mask1) {
+	printk("scanned");
+    } else {
+	/* Fallback: just find interrupts that aren't in use */
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (_check_irq(i, 0) == 0))
+		mask1 |= (1 << i);
+	printk("default");
+	/* If scan failed, default to polled status */
+	if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
+    }
+    printk(") = ");
+    
+    for (i = 0; i < 16; i++)
+	if (mask1 & (1<<i))
+	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+    if (mask1 == 0) printk("none!");
+    
+    return mask1;
+}
+
+#endif /* CONFIG_ISA */
+
+#ifdef CONFIG_PCI
+
+static void pci_scan(u_short sock)
+{
+    u_int i;
+
+    cb_set_irq_mode(sock, 1, 0);
+    set_host_state(sock);
+    i365_set(sock, I365_CSCINT, 0);
+    /* Only probe irq's 9..11, to be conservative */
+    for (i = 9; i < 12; i++) {
+	if ((test_irq(sock, i, 1) == 0) &&
+	    (test_irq(sock, i, 1) == 0))
+	    break;
+    }
+    if (i < 12) socket[sock].cap.pci_irq = i;
+}
+
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+    return ns/cycle_time;
+} /* speed_convert */
+
+static int to_ns(int cycles)
+{
+    return cycle_time*cycles;
+}
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static int identify(u_short port, u_short sock)
+{
+    u_char val;
+    int type = -1;
+
+    /* Use the next free entry in the socket table */
+    socket[sockets].ioaddr = port;
+    socket[sockets].psock = sock;
+    
+    /* Wake up a sleepy Cirrus controller */
+    if (wakeup) {
+	i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
+	/* Pause at least 50 ms */
+	mdelay(50);
+    }
+    
+    if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
+	return -1;
+    switch (val) {
+    case 0x82:
+	type = IS_I82365A; break;
+    case 0x83:
+	type = IS_I82365B; break;
+    case 0x84:
+	type = IS_I82365DF; break;
+    case 0x88: case 0x89: case 0x8a:
+	type = IS_IBM; break;
+    }
+    
+    /* Check for Vadem VG-468 chips */
+    outb(0x0e, port);
+    outb(0x37, port);
+    i365_bset(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+    val = i365_get(sockets, I365_IDENT);
+    if (val & I365_IDENT_VADEM) {
+	i365_bclr(sockets, VG468_MISC, VG468_MISC_VADEMREV);
+	type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
+    }
+
+    /* Check for Ricoh chips */
+    val = i365_get(sockets, RF5C_CHIP_ID);
+    if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
+	type = IS_RF5Cx96;
+    
+    /* Check for Cirrus CL-PD67xx chips */
+    i365_set(sockets, PD67_CHIP_INFO, 0);
+    val = i365_get(sockets, PD67_CHIP_INFO);
+    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+	val = i365_get(sockets, PD67_CHIP_INFO);
+	if ((val & PD67_INFO_CHIP_ID) == 0) {
+	    type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
+	    i365_set(sockets, PD67_EXT_INDEX, 0xe5);
+	    if (i365_get(sockets, PD67_EXT_INDEX) != 0xe5)
+		type = IS_VT83C469;
+	}
+    }
+    return type;
+} /* identify */
+
+#endif
+
+/*======================================================================
+
+    See if a card is present, powered up, in IO mode, and already
+    bound to a (non PC Card) Linux driver.  We leave these alone.
+
+    We make an exception for cards that seem to be serial devices.
+    
+======================================================================*/
+
+static int is_alive(u_short sock)
+{
+    u_char stat;
+    u_short start, stop;
+    
+    stat = i365_get(sock, I365_STATUS);
+    start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
+    stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
+    if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
+	(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
+	(i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
+	(check_region(start, stop-start+1) != 0) &&
+	((start & 0xfeef) != 0x02e8))
+	return 1;
+    else
+	return 0;
+}
+
+/*====================================================================*/
+
+static void add_socket(u_short port, int psock, int type)
+{
+    socket[sockets].ioaddr = port;
+    socket[sockets].psock = psock;
+    socket[sockets].type = type;
+    socket[sockets].flags = pcic[type].flags;
+    if (is_alive(sockets))
+	socket[sockets].flags |= IS_ALIVE;
+    sockets++;
+}
+
+static void add_pcic(int ns, int type)
+{
+    u_int mask = 0, i, base;
+    int use_pci = 0, isa_irq = 0;
+    socket_info_t *t = &socket[sockets-ns];
+
+    base = sockets-ns;
+    if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
+    
+    if (base == 0) printk("\n");
+    printk(KERN_INFO "  %s", pcic[type].name);
+#ifdef CONFIG_PCI
+    if (t->flags & IS_UNKNOWN)
+	printk(" [0x%04x 0x%04x]", t->vendor, t->device);
+    if (t->flags & IS_CARDBUS)
+	printk(" PCI-to-CardBus at bus %d slot %d, mem 0x%08x",
+	       t->bus, PCI_SLOT(t->devfn), t->cb_phys);
+    else if (t->flags & IS_PCI)
+	printk(" PCI-to-PCMCIA at bus %d slot %d, port %#x",
+	       t->bus, PCI_SLOT(t->devfn), t->ioaddr);
+    else
+#endif
+	printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
+	       t->ioaddr, t->psock*0x40);
+    printk(", %d socket%s\n", ns, ((ns > 1) ? "s" : ""));
+
+#ifdef CONFIG_ISA
+    /* Set host options, build basic interrupt mask */
+    if (irq_list[0] == -1)
+	mask = irq_mask;
+    else
+	for (i = mask = 0; i < 16; i++)
+	    mask |= (1<<irq_list[i]);
+#endif
+    mask &= I365_MASK & set_host_opts(base, ns);
+#ifdef CONFIG_ISA
+    /* Scan for ISA interrupts */
+    mask = isa_scan(base, mask);
+#else
+    printk(KERN_INFO "    PCI card interrupts,");
+#endif
+    
+#ifdef CONFIG_PCI
+    /* Can we use a PCI interrupt for card status changes? */
+    if (pci_csc && t->cap.pci_irq) {
+	for (i = 0; i < ns; i++)
+	    if (_check_irq(t[i].cap.pci_irq, SA_SHIRQ)) break;
+	if (i == ns) {
+	    use_pci = 1;
+	    printk(" PCI status changes\n");
+	}
+    }
+#endif
+    
+#ifdef CONFIG_ISA
+    /* Poll if only two interrupts available */
+    if (!use_pci && !poll_interval) {
+	u_int tmp = (mask & (mask-1));
+	if ((tmp & (tmp-1)) == 0)
+	    poll_interval = HZ;
+    }
+    /* Only try an ISA cs_irq if this is the first controller */
+    if (!use_pci && !grab_irq && (cs_irq || !poll_interval)) {
+	/* Avoid irq 12 unless it is explicitly requested */
+	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+	for (cs_irq = 15; cs_irq > 0; cs_irq--)
+	    if ((cs_mask & (1 << cs_irq)) &&
+		(_check_irq(cs_irq, 0) == 0))
+		break;
+	if (cs_irq) {
+	    grab_irq = 1;
+	    isa_irq = cs_irq;
+	    printk(" status change on irq %d\n", cs_irq);
+	}
+    }
+#endif
+    
+    if (!use_pci && !isa_irq) {
+	if (poll_interval == 0)
+	    poll_interval = HZ;
+	printk(" polling interval = %d ms\n",
+	       poll_interval * 1000 / HZ);
+	
+    }
+    
+    /* Update socket interrupt information, capabilities */
+    for (i = 0; i < ns; i++) {
+	t[i].cap.features |= SS_CAP_PCCARD;
+	t[i].cap.map_size = 0x1000;
+	t[i].cap.irq_mask = mask;
+	if (pci_int && t[i].cap.pci_irq)
+	    t[i].cap.irq_mask |= (1 << t[i].cap.pci_irq);
+	t[i].cs_irq = isa_irq;
+#ifdef CONFIG_PCI
+	if (t[i].flags & IS_CARDBUS) {
+	    t[i].cap.features |= SS_CAP_CARDBUS;
+	    cb_set_irq_mode(i, pci_csc && t[i].cap.pci_irq,
+			    pci_int && t[i].cap.pci_irq);
+	}
+#endif
+    }
+
+} /* add_pcic */
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+typedef struct pci_dev *pci_id_t;
+static int pci_lookup(u_int class, pci_id_t *id,
+		      u_char *bus, u_char *devfn)
+{
+    if ((*id = pci_find_class(class<<8, *id)) != NULL) {
+	*bus = (*id)->bus->number;
+	*devfn = (*id)->devfn;
+	return 0;
+    } else return -1;
+}
+
+static void add_pci_bridge(int type, u_char bus, u_char devfn,
+			   u_short v, u_short d)
+{
+    socket_info_t *s = &socket[sockets];
+    u_short i, ns;
+    u_int addr;
+
+    if (type == PCIC_COUNT) type = IS_UNK_PCI;
+    pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &addr);
+    addr &= ~0x1;
+    pci_writew(bus, devfn, PCI_COMMAND, CMD_DFLT);
+    for (i = ns = 0; i < ((type == IS_I82092AA) ? 4 : 2); i++) {
+	s->bus = bus; s->devfn = devfn;
+	s->vendor = v; s->device = d;
+	add_socket(addr, i, type);
+	ns++; s++;
+    }
+    add_pcic(ns, type);
+}
+
+static void add_cb_bridge(int type, u_char bus, u_char devfn,
+			  u_short v, u_short d0)
+{
+    socket_info_t *s = &socket[sockets];
+    u_short d, ns;
+    u_char a, b, r, max;
+    
+    /* PCI bus enumeration is broken on some systems */
+    for (ns = 0; ns < sockets; ns++)
+	if ((socket[ns].bus == bus) && (socket[ns].devfn == devfn))
+	    return;
+    
+    if (type == PCIC_COUNT) type = IS_UNK_CARDBUS;
+    pci_readb(bus, devfn, PCI_HEADER_TYPE, &a);
+    pci_readb(bus, devfn, PCI_CLASS_REVISION, &r);
+    max = (a & 0x80) ? 8 : 1;
+    for (ns = 0; ns < max; ns++, s++, devfn++) {
+	if (pci_readw(bus, devfn, PCI_DEVICE_ID, &d) || (d != d0))
+	    break;
+	s->bus = bus; s->devfn = devfn;
+	s->vendor = v; s->device = d; s->revision = r;
+	
+	/* Check for power management capabilities */
+	pci_readb(bus, devfn, PCI_STATUS, &a);
+	if (a & PCI_STATUS_CAPLIST) {
+	    pci_readb(bus, devfn, PCI_CB_CAPABILITY_POINTER, &b);
+	    while (b != 0) {
+		pci_readb(bus, devfn, b+PCI_CAPABILITY_ID, &a);
+		if (a == PCI_CAPABILITY_PM) {
+		    s->pmcs = b + PCI_PM_CONTROL_STATUS;
+		    break;
+		}
+		pci_readb(bus, devfn, b+PCI_NEXT_CAPABILITY, &b);
+	    }
+	}
+	/* If capability exists, make sure we're in D0 state */
+	if (s->pmcs)
+	    pci_writew(bus, devfn, s->pmcs, PCI_PMCS_PWR_STATE_D0);
+	
+	/* Map CardBus registers if they are not already mapped */
+	pci_writel(bus, devfn, CB_LEGACY_MODE_BASE, 0);
+	pci_readl(bus, devfn, PCI_BASE_ADDRESS_0, &s->cb_phys);
+	if (s->cb_phys == 0) {
+	    int i;
+	    pci_writew(bus, devfn, PCI_COMMAND, CMD_DFLT);
+	    for (i = 0; i < sizeof(cb_mem_base)/sizeof(u_int); i++) {
+		s->cb_phys = cb_mem_base[i];
+		s->cb_virt = ioremap(s->cb_phys, 0x1000);
+		pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, s->cb_phys);
+		/* Simple sanity checks */
+		if (((readb(s->cb_virt+0x800+I365_IDENT) & 0xf0)
+		     == 0x80) &&
+		    !(readb(s->cb_virt+0x800+I365_CSC) &&
+		      readb(s->cb_virt+0x800+I365_CSC) &&
+		      readb(s->cb_virt+0x800+I365_CSC)))
+		    break;
+		iounmap(s->cb_virt);
+	    }
+	    if (i == sizeof(cb_mem_base)/sizeof(u_int)) {
+		pci_writel(bus, devfn, PCI_BASE_ADDRESS_0, 0);
+		s->cb_phys = 0; s->cb_virt = NULL;
+		printk("\n");
+		printk(KERN_NOTICE "  Bridge register mapping failed:"
+		       " check cb_mem_base setting\n");
+		break;
+	    }
+	    cb_mem_base[0] = cb_mem_base[i] + PAGE_SIZE;
+	} else {
+	    s->cb_virt = ioremap(s->cb_phys, 0x1000);
+	}
+	
+	request_mem_region(s->cb_phys, 0x1000, "i82365");
+	add_socket(0, 0, type);
+    }
+    if (ns == 0) return;
+    
+    s -= ns;
+    if (ns == 2) {
+	/* Nasty special check for bad bus mapping */
+	pci_readb(bus, s[0].devfn, CB_CARDBUS_BUS, &a);
+	pci_readb(bus, s[1].devfn, CB_CARDBUS_BUS, &b);
+	if (a == b) {
+	    pci_writeb(bus, s[0].devfn, CB_CARDBUS_BUS, 0);
+	    pci_writeb(bus, s[1].devfn, CB_CARDBUS_BUS, 0);
+	}
+    }
+    add_pcic(ns, type);
+
+    /* Re-do card type & voltage detection */
+    cb_writel(sockets-ns, CB_SOCKET_FORCE, CB_SF_CVSTEST);
+    current->state = TASK_INTERRUPTIBLE;
+    schedule_timeout(HZ/5);
+
+    /* Set up PCI bus bridge structures if needed */
+    for (a = 0; a < ns; a++) {
+	struct pci_dev *self = pci_find_slot(bus, s[a].devfn);
+	struct pci_bus *child, *parent = self->bus;
+	for (child = parent->children; child; child = child->next)
+	    if (child->number == s[a].cap.cardbus) break;
+	if (!child) {
+	    child = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	    memset(child, 0, sizeof(struct pci_bus));
+	    child->self = self;
+	    child->primary = bus;
+	    child->number = child->secondary = s[a].cap.cardbus;
+	    child->subordinate = s[a].sub_bus;
+	    child->parent = parent;
+	    child->ops = parent->ops;
+	    child->next = parent->children;
+	}
+	s[a].cap.cb_bus = parent->children = child;
+    }
+}
+
+static void pci_probe(u_int class, void (add_fn)(int, u_char, u_char,
+						 u_short, u_short))
+{
+    u_short i, v, d;
+    u_char bus, devfn;
+    pci_id_t id;
+    
+    id = 0;
+    while (pci_lookup(class, &id, &bus, &devfn) == 0) {
+	if (PCI_FUNC(devfn) != 0) continue;
+	pci_readw(bus, devfn, PCI_VENDOR_ID, &v);
+	pci_readw(bus, devfn, PCI_DEVICE_ID, &d);
+	for (i = 0; i < PCIC_COUNT; i++)
+	    if ((pcic[i].vendor == v) && (pcic[i].device == d)) break;
+	add_fn(i, bus, devfn, v, d);
+    }
+}
+
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void isa_probe(void)
+{
+    int i, j, sock, k;
+    int ns, id;
+    u_short port;
+
+    if (check_region(i365_base, 2) != 0) {
+	if (sockets == 0)
+	    printk("port conflict at %#x\n", i365_base);
+	return;
+    }
+
+    id = identify(i365_base, 0);
+    if ((id == IS_I82365DF) && (identify(i365_base, 1) != id)) {
+	for (i = 0; i < 4; i++) {
+	    if (i == ignore) continue;
+	    port = i365_base + ((i & 1) << 2) + ((i & 2) << 1);
+	    sock = (i & 1) << 1;
+	    if (identify(port, sock) == IS_I82365DF) {
+		add_socket(port, sock, IS_VLSI);
+		add_pcic(1, IS_VLSI);
+	    }
+	}
+    } else {
+	for (i = 0; i < (extra_sockets ? 8 : 4); i += 2) {
+	    port = i365_base + 2*(i>>2);
+	    sock = (i & 3);
+	    id = identify(port, sock);
+	    if (id < 0) continue;
+
+	    for (j = ns = 0; j < 2; j++) {
+		/* Does the socket exist? */
+		if ((ignore == i+j) || (identify(port, sock+j) < 0))
+		    continue;
+		/* Check for bad socket decode */
+		for (k = 0; k <= sockets; k++)
+		    i365_set(k, I365_MEM(0)+I365_W_OFF, k);
+		for (k = 0; k <= sockets; k++)
+		    if (i365_get(k, I365_MEM(0)+I365_W_OFF) != k)
+			break;
+		if (k <= sockets) break;
+		add_socket(port, sock+j, id); ns++;
+	    }
+	    if (ns != 0) add_pcic(ns, id);
+	}
+    }
+}
+
+#endif
+
+/*====================================================================*/
+
+static int pcic_init(void)
+{
+    DEBUG(0, "%s\n", version);
+    printk(KERN_INFO "Intel PCIC probe: ");
+    sockets = 0;
+
+#ifdef CONFIG_PCI
+    if (do_pci_probe && pcibios_present()) {
+	pci_probe(PCI_CLASS_BRIDGE_CARDBUS, add_cb_bridge);
+	pci_probe(PCI_CLASS_BRIDGE_PCMCIA, add_pci_bridge);
+    }
+#endif
+
+#ifdef CONFIG_ISA
+    isa_probe();
+#endif
+
+    if (sockets == 0) {
+	printk("not found.\n");
+	return -ENODEV;
+    }
+
+    /* Set up interrupt handler, and/or polling */
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	request_irq(cs_irq, pcic_interrupt, 0, "i82365", NULL);
+#endif
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+	u_int i, irq, mask = 0;
+	for (i = 0; i < sockets; i++) {
+	    irq = socket[i].cap.pci_irq;
+	    if (irq && !(mask & (1<<irq)))
+		request_irq(irq, pcic_interrupt, SA_SHIRQ, "i82365", NULL);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    
+    if (register_ss_entry(sockets, &pcic_service) != 0)
+	printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
+
+    /* Finally, schedule a polling interrupt */
+    if (poll_interval != 0) {
+	poll_timer.function = pcic_interrupt_wrapper;
+	poll_timer.data = 0;
+	poll_timer.prev = poll_timer.next = NULL;
+    	poll_timer.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+    }
+    
+    return 0;
+    
+} /* pcic_init */
+  
+/*====================================================================*/
+
+static void pcic_finish(void)
+{
+    int i;
+#ifdef CONFIG_PROC_FS
+    for (i = 0; i < sockets; i++) pcic_proc_remove(i);
+#endif
+    unregister_ss_entry(&pcic_service);
+    if (poll_interval != 0)
+	del_timer(&poll_timer);
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	free_irq(cs_irq, NULL);
+#endif
+#ifdef CONFIG_PCI
+    if (pci_csc) {
+	u_int irq, mask = 0;
+	for (i = 0; i < sockets; i++) {
+	    irq = socket[i].cap.pci_irq;
+	    if (irq && !(mask & (1<<irq)))
+		free_irq(irq, NULL);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    for (i = 0; i < sockets; i++) {
+	i365_set(i, I365_CSCINT, 0);
+#ifdef CONFIG_PCI
+	if (socket[i].cb_virt) {
+	    iounmap(socket[i].cb_virt);
+	    release_mem_region(socket[i].cb_phys, 0x1000);
+	} else
+#endif
+	    release_region(socket[i].ioaddr, 2);
+    }
+} /* pcic_finish */
+
+/*====================================================================*/
+
+static void pcic_interrupt_wrapper(u_long data)
+{
+    pcic_interrupt(0, NULL, NULL);
+    poll_timer.expires = jiffies + poll_interval;
+    add_timer(&poll_timer);
+}
+
+static void pcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+    int i, j, csc;
+    u_int events, active;
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+    
+    DEBUG(4, "i82365: pcic_interrupt(%d)\n", irq);
+
+    for (j = 0; j < 20; j++) {
+	active = 0;
+	for (i = 0; i < sockets; i++) {
+	    if ((socket[i].cs_irq != irq) &&
+		(socket[i].cap.pci_irq != irq))
+		continue;
+#ifdef CONFIG_ISA
+	    if (!(socket[i].flags & IS_CARDBUS))
+		spin_lock_irqsave(&isa_lock, flags);
+#endif
+	    csc = i365_get(i, I365_CSC);
+	    if ((csc == 0) || (!socket[i].handler) ||
+		(i365_get(i, I365_IDENT) & 0x70)) {
+#ifdef CONFIG_ISA
+		if (!(socket[i].flags & IS_CARDBUS))
+		    spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+		continue;
+	    }
+	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+	    if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+	    else {
+		events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+		events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+		events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+	    }
+#ifdef CONFIG_ISA
+	    if (!(socket[i].flags & IS_CARDBUS))
+		spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+	    DEBUG(2, "i82365: socket %d event 0x%02x\n", i, events);
+	    if (events)
+		socket[i].handler(socket[i].info, events);
+	    active |= events;
+	}
+	if (!active) break;
+    }
+    if (j == 20)
+	printk(KERN_NOTICE "i82365: infinite loop in interrupt handler\n");
+
+    DEBUG(4, ("i82365: interrupt done\n"));
+} /* pcic_interrupt */
+
+/*====================================================================*/
+
+static int pcic_register_callback(u_short sock, ss_callback_t *call)
+{
+    if (call == NULL) {
+	socket[sock].handler = NULL;
+	MOD_DEC_USE_COUNT;
+    } else {
+	MOD_INC_USE_COUNT;
+	socket[sock].handler = call->handler;
+	socket[sock].info = call->info;
+    }
+    return 0;
+} /* pcic_register_callback */
+
+/*====================================================================*/
+
+static int pcic_inquire_socket(u_short sock, socket_cap_t *cap)
+{
+    *cap = socket[sock].cap;
+    return 0;
+} /* pcic_inquire_socket */
+
+/*====================================================================*/
+
+static int i365_get_status(u_short sock, u_int *value)
+{
+    u_int status;
+    
+    status = i365_get(sock, I365_STATUS);
+    *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+	? SS_DETECT : 0;
+    if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+	*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+    else {
+	*value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD;
+	*value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN;
+    }
+    *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0;
+    *value |= (status & I365_CS_READY) ? SS_READY : 0;
+    *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0;
+
+#ifdef CONFIG_PCI
+    if (socket[sock].flags & IS_CARDBUS) {
+	status = cb_readl(sock, CB_SOCKET_STATE);
+#ifndef CONFIG_CARDBUS
+	*value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0;
+#endif
+	*value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0;
+	*value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0;
+    } else if (socket[sock].flags & IS_O2MICRO) {
+	status = i365_get(sock, O2_MODE_B);
+	*value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD;
+	*value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD;
+    }
+#endif
+#ifdef CONFIG_ISA
+    if (socket[sock].type == IS_VG469) {
+	status = i365_get(sock, VG469_VSENSE);
+	if (socket[sock].psock & 1) {
+	    *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD;
+	    *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD;
+	} else {
+	    *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD;
+	    *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
+	}
+    }
+#endif
+    
+    DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value);
+    return 0;
+} /* i365_get_status */
+
+/*====================================================================*/
+
+static int i365_get_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *t = &socket[sock];
+    u_char reg, vcc, vpp;
+    
+    reg = i365_get(sock, I365_POWER);
+    state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
+    state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
+    vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK;
+    state->Vcc = state->Vpp = 0;
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS) {
+	cb_get_power(sock, state);
+    } else
+#endif
+    if (t->flags & IS_CIRRUS) {
+	if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) {
+	    if (reg & I365_VCC_5V) state->Vcc = 33;
+	    if (vpp == I365_VPP1_5V) state->Vpp = 33;
+	} else {
+	    if (reg & I365_VCC_5V) state->Vcc = 50;
+	    if (vpp == I365_VPP1_5V) state->Vpp = 50;
+	}
+	if (vpp == I365_VPP1_12V) state->Vpp = 120;
+    } else if (t->flags & IS_VG_PWR) {
+	if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) {
+	    if (reg & I365_VCC_5V) state->Vcc = 33;
+	    if (vpp == I365_VPP1_5V) state->Vpp = 33;
+	} else {
+	    if (reg & I365_VCC_5V) state->Vcc = 50;
+	    if (vpp == I365_VPP1_5V) state->Vpp = 50;
+	}
+	if (vpp == I365_VPP1_12V) state->Vpp = 120;
+    } else if (t->flags & IS_DF_PWR) {
+	if (vcc == I365_VCC_3V) state->Vcc = 33;
+	if (vcc == I365_VCC_5V) state->Vcc = 50;
+	if (vpp == I365_VPP1_5V) state->Vpp = 50;
+	if (vpp == I365_VPP1_12V) state->Vpp = 120;
+    } else {
+	if (reg & I365_VCC_5V) {
+	    state->Vcc = 50;
+	    if (vpp == I365_VPP1_5V) state->Vpp = 50;
+	    if (vpp == I365_VPP1_12V) state->Vpp = 120;
+	}
+    }
+
+    /* IO card, RESET flags, IO interrupt */
+    reg = i365_get(sock, I365_INTCTL);
+    state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+    if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD;
+#ifdef CONFIG_PCI
+    if (cb_get_irq_mode(sock) != 0)
+	state->io_irq = t->cap.pci_irq;
+    else
+#endif
+	state->io_irq = reg & I365_IRQ_MASK;
+    
+    /* speaker control */
+    if (t->flags & IS_CIRRUS) {
+	if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA)
+	    state->flags |= SS_SPKR_ENA;
+    }
+    
+    /* Card status change mask */
+    reg = i365_get(sock, I365_CSCINT);
+    state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0;
+    if (state->flags & SS_IOCARD)
+	state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+    else {
+	state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+	state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0;
+	state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
+    }
+    
+    DEBUG(1, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    return 0;
+} /* i365_get_socket */
+
+/*====================================================================*/
+
+static int i365_set_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *t = &socket[sock];
+    u_char reg;
+    
+    DEBUG(1, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    
+    /* First set global controller options */
+#ifdef CONFIG_PCI
+    if ((t->flags & IS_CARDBUS) && t->cap.pci_irq)
+	cb_set_irq_mode(sock, pci_csc,
+			(t->cap.pci_irq == state->io_irq));
+    t->bcr &= ~CB_BCR_CB_RESET;
+#endif
+    set_host_state(sock);
+    
+    /* IO card, RESET flag, IO interrupt */
+    reg = t->intr;
+    if (state->io_irq != t->cap.pci_irq) reg |= state->io_irq;
+    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+    i365_set(sock, I365_INTCTL, reg);
+    
+    reg = I365_PWR_NORESET;
+    if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
+    if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+
+#ifdef CONFIG_PCI
+    if (t->flags & IS_CARDBUS) {
+	cb_set_power(sock, state);
+	reg |= i365_get(sock, I365_POWER) &
+	    (I365_VCC_MASK|I365_VPP1_MASK);
+    } else
+#endif
+    if (t->flags & IS_CIRRUS) {
+	if (state->Vpp != 0) {
+	    if (state->Vpp == 120)
+		reg |= I365_VPP1_12V;
+	    else if (state->Vpp == state->Vcc)
+		reg |= I365_VPP1_5V;
+	    else return -EINVAL;
+	}
+	if (state->Vcc != 0) {
+	    reg |= I365_VCC_5V;
+	    if (state->Vcc == 33)
+		i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+	    else if (state->Vcc == 50)
+		i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+	    else return -EINVAL;
+	}
+    } else if (t->flags & IS_VG_PWR) {
+	if (state->Vpp != 0) {
+	    if (state->Vpp == 120)
+		reg |= I365_VPP1_12V;
+	    else if (state->Vpp == state->Vcc)
+		reg |= I365_VPP1_5V;
+	    else return -EINVAL;
+	}
+	if (state->Vcc != 0) {
+	    reg |= I365_VCC_5V;
+	    if (state->Vcc == 33)
+		i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC);
+	    else if (state->Vcc == 50)
+		i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC);
+	    else return -EINVAL;
+	}
+    } else if (t->flags & IS_DF_PWR) {
+	switch (state->Vcc) {
+	case 0:		break;
+	case 33:   	reg |= I365_VCC_3V; break;
+	case 50:	reg |= I365_VCC_5V; break;
+	default:	return -EINVAL;
+	}
+	switch (state->Vpp) {
+	case 0:		break;
+	case 50:   	reg |= I365_VPP1_5V; break;
+	case 120:	reg |= I365_VPP1_12V; break;
+	default:	return -EINVAL;
+	}
+    } else {
+	switch (state->Vcc) {
+	case 0:		break;
+	case 50:	reg |= I365_VCC_5V; break;
+	default:	return -EINVAL;
+	}
+	switch (state->Vpp) {
+	case 0:		break;
+	case 50:	reg |= I365_VPP1_5V | I365_VPP2_5V; break;
+	case 120:	reg |= I365_VPP1_12V | I365_VPP2_12V; break;
+	default:	return -EINVAL;
+	}
+    }
+    
+    if (reg != i365_get(sock, I365_POWER))
+	i365_set(sock, I365_POWER, reg);
+
+    /* Chipset-specific functions */
+    if (t->flags & IS_CIRRUS) {
+	/* Speaker control */
+	i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
+		   state->flags & SS_SPKR_ENA);
+    }
+    
+    /* Card status change interrupt mask */
+    reg = t->cs_irq << 4;
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    if (state->flags & SS_IOCARD) {
+	if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+    } else {
+	if (state->csc_mask & SS_BATDEAD) reg |= I365_CSC_BVD1;
+	if (state->csc_mask & SS_BATWARN) reg |= I365_CSC_BVD2;
+	if (state->csc_mask & SS_READY) reg |= I365_CSC_READY;
+    }
+    i365_set(sock, I365_CSCINT, reg);
+    i365_get(sock, I365_CSC);
+    
+    return 0;
+} /* i365_set_socket */
+
+/*====================================================================*/
+
+static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl, addr;
+    
+    map = io->map;
+    if (map > 1) return -EINVAL;
+    io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
+    io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP);
+    ioctl = i365_get(sock, I365_IOCTL);
+    addr = i365_get(sock, I365_ADDRWIN);
+    io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0;
+    io->flags  = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0;
+    io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0;
+    io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0;
+    io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0;
+    DEBUG(1, "i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+	  "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed,
+	  io->start, io->stop);
+    return 0;
+} /* i365_get_io_map */
+
+/*====================================================================*/
+
+static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
+{
+    u_char map, ioctl;
+    
+    DEBUG(1, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
+	  "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+	  io->speed, io->start, io->stop);
+    map = io->map;
+    if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+	(io->stop < io->start)) return -EINVAL;
+    /* Turn off the window before changing anything */
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map))
+	i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start);
+    i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop);
+    ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
+    if (io->speed) ioctl |= I365_IOCTL_WAIT(map);
+    if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
+    if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+    if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+    i365_set(sock, I365_IOCTL, ioctl);
+    /* Turn on the window if necessary */
+    if (io->flags & MAP_ACTIVE)
+	i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map));
+    return 0;
+} /* i365_set_io_map */
+
+/*====================================================================*/
+
+static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map, addr;
+    
+    map = mem->map;
+    if (map > 4) return -EINVAL;
+    addr = i365_get(sock, I365_ADDRWIN);
+    mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
+    base = I365_MEM(map);
+    
+    i = i365_get_pair(sock, base+I365_W_START);
+    mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0;
+    mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0;
+    mem->sys_start += ((u_long)(i & 0x0fff) << 12);
+    
+    i = i365_get_pair(sock, base+I365_W_STOP);
+    mem->speed  = (i & I365_MEM_WS0) ? 1 : 0;
+    mem->speed += (i & I365_MEM_WS1) ? 2 : 0;
+    mem->speed = to_ns(mem->speed);
+    mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff;
+    
+    i = i365_get_pair(sock, base+I365_W_OFF);
+    mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0;
+    mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0;
+    mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start;
+    mem->card_start &= 0x3ffffff;
+
+#ifdef CONFIG_PCI
+    /* Take care of high byte, for PCI controllers */
+    if (socket[sock].type == IS_PD6729) {
+	i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+	addr = i365_get(sock, PD67_EXT_DATA) << 24;
+    } else if (socket[sock].flags & IS_CARDBUS) {
+	addr = i365_get(sock, CB_MEM_PAGE(map)) << 24;
+	mem->sys_stop += addr; mem->sys_start += addr;
+    }
+#endif
+    
+    DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+	  "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
+	  mem->sys_start, mem->sys_stop, mem->card_start);
+    return 0;
+} /* i365_get_mem_map */
+
+/*====================================================================*/
+  
+static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map;
+    
+    DEBUG(1, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+	  "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
+	  mem->sys_start, mem->sys_stop, mem->card_start);
+
+    map = mem->map;
+    if ((map > 4) || (mem->card_start > 0x3ffffff) ||
+	(mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+	return -EINVAL;
+    if (!(socket[sock].flags & (IS_PCI | IS_CARDBUS)) &&
+	((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff)))
+	return -EINVAL;
+	
+    /* Turn off the window before changing anything */
+    if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+	i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+
+#ifdef CONFIG_PCI
+    /* Take care of high byte, for PCI controllers */
+    if (socket[sock].type == IS_PD6729) {
+	i365_set(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+	i365_set(sock, PD67_EXT_DATA, (mem->sys_start >> 24));
+    } else if (socket[sock].flags & IS_CARDBUS)
+	i365_set(sock, CB_MEM_PAGE(map), mem->sys_start >> 24);
+#endif
+    
+    base = I365_MEM(map);
+    i = (mem->sys_start >> 12) & 0x0fff;
+    if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
+    if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
+    i365_set_pair(sock, base+I365_W_START, i);
+    
+    i = (mem->sys_stop >> 12) & 0x0fff;
+    switch (to_cycles(mem->speed)) {
+    case 0:	break;
+    case 1:	i |= I365_MEM_WS0; break;
+    case 2:	i |= I365_MEM_WS1; break;
+    default:	i |= I365_MEM_WS1 | I365_MEM_WS0; break;
+    }
+    i365_set_pair(sock, base+I365_W_STOP, i);
+    
+    i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+    if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
+    if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
+    i365_set_pair(sock, base+I365_W_OFF, i);
+    
+    /* Turn on the window if necessary */
+    if (mem->flags & MAP_ACTIVE)
+	i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+    return 0;
+} /* i365_set_mem_map */
+
+/*======================================================================
+
+    Power control for Cardbus controllers: used both for 16-bit and
+    Cardbus cards.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_power(u_short sock, socket_state_t *state)
+{
+    u_int reg = cb_readl(sock, CB_SOCKET_CONTROL);
+    state->Vcc = state->Vpp = 0;
+    switch (reg & CB_SC_VCC_MASK) {
+    case CB_SC_VCC_3V:		state->Vcc = 33; break;
+    case CB_SC_VCC_5V:		state->Vcc = 50; break;
+    }
+    switch (reg & CB_SC_VCC_MASK) {
+    case CB_SC_VPP_3V:		state->Vpp = 33; break;
+    case CB_SC_VPP_5V:		state->Vpp = 50; break;
+    case CB_SC_VPP_12V:		state->Vpp = 120; break;
+    }
+}
+
+static void cb_set_power(u_short sock, socket_state_t *state)
+{
+    u_int reg = 0;
+    switch (state->Vcc) {
+    case 33:		reg = CB_SC_VCC_3V; break;
+    case 50:		reg = CB_SC_VCC_5V; break;
+    default:		reg = 0; break;
+    }
+    switch (state->Vpp) {
+    case 33:		reg |= CB_SC_VPP_3V; break;
+    case 50:		reg |= CB_SC_VPP_5V; break;
+    case 120:		reg |= CB_SC_VPP_12V; break;
+    }
+    if (reg != cb_readl(sock, CB_SOCKET_CONTROL))
+	cb_writel(sock, CB_SOCKET_CONTROL, reg);
+}
+
+#endif
+
+/*======================================================================
+
+    All the stuff that is strictly for Cardbus cards goes here.
+    
+======================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int cb_get_status(u_short sock, u_int *value)
+{
+    u_int s;
+    s = cb_readl(sock, CB_SOCKET_STATE);
+    *value = ((s & CB_SS_32BIT) ? SS_CARDBUS : 0);
+    *value |= ((s & CB_SS_CCD1) || (s & CB_SS_CCD2)) ? 0 : SS_DETECT;
+    *value |= (s & CB_SS_CSTSCHG) ? SS_STSCHG : 0;
+    *value |= (s & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0;
+    *value |= (s & CB_SS_3VCARD) ? SS_3VCARD : 0;
+    *value |= (s & CB_SS_XVCARD) ? SS_XVCARD : 0;
+    DEBUG(1, "yenta: GetStatus(%d) = %#4.4x\n", sock, *value);
+    return 0;
+} /* cb_get_status */
+
+static int cb_get_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *s = &socket[sock];
+    u_short bcr;
+
+    cb_get_power(sock, state);
+    pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+    state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0;
+    if (cb_get_irq_mode(sock) != 0)
+	state->io_irq = s->cap.pci_irq;
+    else
+	state->io_irq = i365_get(sock, I365_INTCTL) & I365_IRQ_MASK;
+    DEBUG(1, "yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    return 0;
+} /* cb_get_socket */
+
+static int cb_set_socket(u_short sock, socket_state_t *state)
+{
+    socket_info_t *s = &socket[sock];
+    u_int reg;
+    
+    DEBUG(1, "yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    
+    /* First set global controller options */
+    if (s->cap.pci_irq)
+	cb_set_irq_mode(sock, pci_csc,
+			(s->cap.pci_irq == state->io_irq));
+    s->bcr &= ~CB_BCR_CB_RESET;
+    s->bcr |= (state->flags & SS_RESET) ? CB_BCR_CB_RESET : 0;
+    set_host_state(sock);
+    
+    cb_set_power(sock, state);
+    
+    /* Handle IO interrupt using ISA routing */
+    reg = i365_get(sock, I365_INTCTL) & ~I365_IRQ_MASK;
+    if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq;
+    i365_set(sock, I365_INTCTL, reg);
+    
+    /* Handle CSC mask */
+    reg = (socket[sock].cs_irq << 4);
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    i365_set(sock, I365_CSCINT, reg);
+    i365_get(sock, I365_CSC);
+    
+    return 0;
+} /* cb_set_socket */
+
+static int cb_get_bridge(u_short sock, struct cb_bridge_map *m)
+{
+    socket_info_t *s = &socket[sock];
+    u_char map;
+    
+    map = m->map;
+    if (map > 1) return -EINVAL;
+    m->flags &= MAP_IOSPACE;
+    map += (m->flags & MAP_IOSPACE) ? 2 : 0;
+    pci_readl(s->bus, s->devfn, CB_MEM_BASE(map), &m->start);
+    pci_readl(s->bus, s->devfn, CB_MEM_LIMIT(map), &m->stop);
+    if (m->start || m->stop) {
+	m->flags |= MAP_ACTIVE;
+	m->stop |= (map > 1) ? 3 : 0x0fff;
+    }
+    if (map > 1) {
+	u_short bcr;
+	pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+	m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0;
+    }
+    DEBUG(1, "yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n",
+	  sock, map, m->flags, m->start, m->stop);
+    return 0;
+}
+
+static int cb_set_bridge(u_short sock, struct cb_bridge_map *m)
+{
+    socket_info_t *s = &socket[sock];
+    u_char map;
+    
+    DEBUG(1, "yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n",
+	  sock, m->map, m->flags, m->start, m->stop);
+    map = m->map;
+    if (!(s->flags & IS_CARDBUS) || (map > 1) || (m->stop < m->start))
+	return -EINVAL;
+    if (m->flags & MAP_IOSPACE) {
+	if ((m->stop > 0xffff) || (m->start & 3) ||
+	    ((m->stop & 3) != 3))
+	    return -EINVAL;
+	map += 2;
+    } else {
+	u_short bcr;
+	if ((m->start & 0x0fff) || ((m->stop & 0x0fff) != 0x0fff))
+	    return -EINVAL;
+	pci_readw(s->bus, s->devfn, CB_BRIDGE_CONTROL, &bcr);
+	bcr &= ~CB_BCR_PREFETCH(map);
+	bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0;
+	pci_writew(s->bus, s->devfn, CB_BRIDGE_CONTROL, bcr);
+    }
+    if (m->flags & MAP_ACTIVE) {
+	pci_writel(s->bus, s->devfn, CB_MEM_BASE(map), m->start);
+	pci_writel(s->bus, s->devfn, CB_MEM_LIMIT(map), m->stop);
+    } else {
+	pci_writel(s->bus, s->devfn, CB_IO_BASE(map), 0);
+	pci_writel(s->bus, s->devfn, CB_IO_LIMIT(map), 0);
+    }
+    return 0;
+}
+
+#endif /* CONFIG_CARDBUS */
+
+/*======================================================================
+
+    Routines for accessing socket information and register dumps via
+    /proc/bus/pccard/...
+    
+======================================================================*/
+
+#ifdef CONFIG_PROC_FS
+
+static int proc_read_info(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    char *p = buf;
+    p += sprintf(p, "type:     %s\npsock:    %d\n",
+		 pcic[s->type].name, s->psock);
+#ifdef CONFIG_PCI
+    if (s->flags & (IS_PCI|IS_CARDBUS))
+	p += sprintf(p, "bus:      %02x\ndevfn:    %02x.%1x\n",
+		     s->bus, PCI_SLOT(s->devfn), PCI_FUNC(s->devfn));
+    if (s->flags & IS_CARDBUS)
+	p += sprintf(p, "cardbus:  %02x\n", s->cap.cardbus);
+#endif
+    return (p - buf);
+}
+
+static int proc_read_exca(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+    u_short sock = (socket_info_t *)data - socket;
+    char *p = buf;
+    int i, top;
+    
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+    if (!(socket[sock].flags & IS_CARDBUS))
+	spin_lock_irqsave(&isa_lock, flags);
+#endif
+    top = 0x40;
+    if (socket[sock].flags & IS_CARDBUS)
+	top = (socket[sock].flags & IS_CIRRUS) ? 0x140 : 0x50;
+    for (i = 0; i < top; i += 4) {
+	if (i == 0x50) {
+	    p += sprintf(p, "\n");
+	    i = 0x100;
+	}
+	p += sprintf(p, "%02x %02x %02x %02x%s",
+		     i365_get(sock,i), i365_get(sock,i+1),
+		     i365_get(sock,i+2), i365_get(sock,i+3),
+		     ((i % 16) == 12) ? "\n" : " ");
+    }
+#ifdef CONFIG_ISA
+    if (!(socket[sock].flags & IS_CARDBUS))
+	spin_unlock_irqrestore(&isa_lock, flags);
+#endif
+    return (p - buf);
+}
+
+
+#ifdef CONFIG_PCI
+static int proc_read_pci(char *buf, char **start, off_t pos,
+			 int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    u_char bus = s->bus, devfn = s->devfn;
+    char *p = buf;
+    u_int a, b, c, d;
+    int i;
+    
+    for (i = 0; i < 0xc0; i += 0x10) {
+	pci_readl(bus, devfn, i, &a);
+	pci_readl(bus, devfn, i+4, &b);
+	pci_readl(bus, devfn, i+8, &c);
+	pci_readl(bus, devfn, i+12, &d);
+	p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d);
+    }
+    return (p - buf);
+}
+#endif
+
+#ifdef CONFIG_CARDBUS
+static int proc_read_cardbus(char *buf, char **start, off_t pos,
+			     int count, int *eof, void *data)
+{
+    u_short sock = (socket_info_t *)data - socket;
+    int len;
+    
+    len = sprintf(buf, "%08x %08x %08x %08x %08x %08x\n",
+		  cb_readl(sock,0), cb_readl(sock,4),
+		  cb_readl(sock,8), cb_readl(sock,12),
+		  cb_readl(sock,16), cb_readl(sock,32));
+    return len;
+}
+#endif
+
+static void pcic_proc_setup(u_short sock, struct proc_dir_entry *base)
+{
+    socket_info_t *s = &socket[sock];
+    struct proc_dir_entry *ent;
+    ent = create_proc_entry("info", 0, base);
+    ent->read_proc = proc_read_info;
+    ent->data = s;
+    ent = create_proc_entry("exca", 0, base);
+    ent->read_proc = proc_read_exca;
+    ent->data = s;
+#ifdef CONFIG_PCI
+    if (s->flags & (IS_PCI|IS_CARDBUS)) {
+	ent = create_proc_entry("pci", 0, base);
+	ent->read_proc = proc_read_pci;
+	ent->data = s;
+    }
+#endif
+#ifdef CONFIG_CARDBUS
+    if (s->flags & IS_CARDBUS) {
+	ent = create_proc_entry("cardbus", 0, base);
+	ent->read_proc = proc_read_cardbus;
+	ent->data = s;
+    }
+#endif
+    s->proc = base;
+}
+
+static void pcic_proc_remove(u_short sock)
+{
+    struct proc_dir_entry *base = socket[sock].proc;
+    if (base == NULL) return;
+    remove_proc_entry("info", base);
+    remove_proc_entry("exca", base);
+#ifdef CONFIG_PCI
+    if (socket[sock].flags & (IS_PCI|IS_CARDBUS))
+	remove_proc_entry("pci", base);
+#endif
+#ifdef CONFIG_CARDBUS
+    if (socket[sock].flags & IS_CARDBUS)
+	remove_proc_entry("cardbus", base);
+#endif
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(u_short, void *);
+
+static subfn_t pcic_service_table[] = {
+    (subfn_t)&pcic_register_callback,
+    (subfn_t)&pcic_inquire_socket,
+    (subfn_t)&i365_get_status,
+    (subfn_t)&i365_get_socket,
+    (subfn_t)&i365_set_socket,
+    (subfn_t)&i365_get_io_map,
+    (subfn_t)&i365_set_io_map,
+    (subfn_t)&i365_get_mem_map,
+    (subfn_t)&i365_set_mem_map,
+#ifdef CONFIG_CARDBUS
+    (subfn_t)&cb_get_bridge,
+    (subfn_t)&cb_set_bridge,
+#else
+    NULL, NULL,
+#endif
+#ifdef CONFIG_PROC_FS
+    (subfn_t)&pcic_proc_setup
+#endif
+};
+
+#define NFUNC (sizeof(pcic_service_table)/sizeof(subfn_t))
+
+static int pcic_service(u_int sock, u_int cmd, void *arg)
+{
+    subfn_t fn;
+
+    DEBUG(2, "pcic_ioctl(%d, %d, 0x%p)\n", sock, cmd, arg);
+
+    if (cmd >= NFUNC)
+	return -EINVAL;
+
+    if (socket[sock].flags & IS_ALIVE) {
+	if (cmd == SS_GetStatus)
+	    *(u_int *)arg = 0;
+	return -EINVAL;
+    }
+    
+    fn = pcic_service_table[cmd];
+#ifdef CONFIG_CARDBUS
+    if ((socket[sock].flags & IS_CARDBUS) &&
+	(cb_readl(sock, CB_SOCKET_STATE) & CB_SS_32BIT)) {
+	if (cmd == SS_GetStatus)
+	    fn = (subfn_t)&cb_get_status;
+	else if (cmd == SS_GetSocket)
+	    fn = (subfn_t)&cb_get_socket;
+	else if (cmd == SS_SetSocket)
+	    fn = (subfn_t)&cb_set_socket;
+    }
+#endif
+
+#ifdef CONFIG_ISA
+    if (!(socket[sock].flags & IS_CARDBUS)) {
+	int ret;
+	u_long flags;
+	spin_lock_irqsave(&isa_lock, flags);
+	ret = (fn == NULL) ? -EINVAL : fn(sock, arg);
+	spin_unlock_irqrestore(&isa_lock, flags);
+	return ret;
+    }
+#endif
+    return (fn == NULL) ? -EINVAL : fn(sock, arg);
+} /* pcic_service */
+
+/*====================================================================*/
+
+int pcmcia_i82365_init(void)
+{
+    servinfo_t serv;
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "i82365: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    return pcic_init();
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	return pcmcia_i82365_init();
+}
+
+void cleanup_module(void)
+{
+    pcic_finish();
+}
+
+#endif
+
+/*====================================================================*/
+
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/i82365.h linux/drivers/pcmcia/i82365.h
--- v2.3.16/linux/drivers/pcmcia/i82365.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/i82365.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,135 @@
+/*
+ * i82365.h 1.14 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_I82365_H
+#define _LINUX_I82365_H
+
+/* register definitions for the Intel 82365SL PCMCIA controller */
+
+/* Offsets for PCIC registers */
+#define I365_IDENT	0x00	/* Identification and revision */
+#define I365_STATUS	0x01	/* Interface status */
+#define I365_POWER	0x02	/* Power and RESETDRV control */
+#define I365_INTCTL	0x03	/* Interrupt and general control */
+#define I365_CSC	0x04	/* Card status change */
+#define I365_CSCINT	0x05	/* Card status change interrupt control */
+#define I365_ADDRWIN	0x06	/* Address window enable */
+#define I365_IOCTL	0x07	/* I/O control */
+#define I365_GENCTL	0x16	/* Card detect and general control */
+#define I365_GBLCTL	0x1E	/* Global control register */
+
+/* Offsets for I/O and memory window registers */
+#define I365_IO(map)	(0x08+((map)<<2))
+#define I365_MEM(map)	(0x10+((map)<<3))
+#define I365_W_START	0
+#define I365_W_STOP	2
+#define I365_W_OFF	4
+
+/* Flags for I365_STATUS */
+#define I365_CS_BVD1	0x01
+#define I365_CS_STSCHG	0x01
+#define I365_CS_BVD2	0x02
+#define I365_CS_SPKR	0x02
+#define I365_CS_DETECT	0x0C
+#define I365_CS_WRPROT	0x10
+#define I365_CS_READY	0x20	/* Inverted */
+#define I365_CS_POWERON	0x40
+#define I365_CS_GPI	0x80
+
+/* Flags for I365_POWER */
+#define I365_PWR_OFF	0x00	/* Turn off the socket */
+#define I365_PWR_OUT	0x80	/* Output enable */
+#define I365_PWR_NORESET 0x40	/* Disable RESETDRV on resume */
+#define I365_PWR_AUTO	0x20	/* Auto pwr switch enable */
+#define I365_VCC_MASK	0x18	/* Mask for turning off Vcc */
+/* There are different layouts for B-step and DF-step chips: the B
+   step has independent Vpp1/Vpp2 control, and the DF step has only
+   Vpp1 control, plus 3V control */
+#define I365_VCC_5V	0x10	/* Vcc = 5.0v */
+#define I365_VCC_3V	0x18	/* Vcc = 3.3v */
+#define I365_VPP2_MASK	0x0c	/* Mask for turning off Vpp2 */
+#define I365_VPP2_5V	0x04	/* Vpp2 = 5.0v */
+#define I365_VPP2_12V	0x08	/* Vpp2 = 12.0v */
+#define I365_VPP1_MASK	0x03	/* Mask for turning off Vpp1 */
+#define I365_VPP1_5V	0x01	/* Vpp2 = 5.0v */
+#define I365_VPP1_12V	0x02	/* Vpp2 = 12.0v */
+
+/* Flags for I365_INTCTL */
+#define I365_RING_ENA	0x80
+#define I365_PC_RESET	0x40
+#define I365_PC_IOCARD	0x20
+#define I365_INTR_ENA	0x10
+#define I365_IRQ_MASK	0x0F
+
+/* Flags for I365_CSC and I365_CSCINT*/
+#define I365_CSC_BVD1	0x01
+#define I365_CSC_STSCHG	0x01
+#define I365_CSC_BVD2	0x02
+#define I365_CSC_READY	0x04
+#define I365_CSC_DETECT	0x08
+#define I365_CSC_ANY	0x0F
+#define I365_CSC_GPI	0x10
+
+/* Flags for I365_ADDRWIN */
+#define I365_ENA_IO(map)	(0x40 << (map))
+#define I365_ENA_MEM(map)	(0x01 << (map))
+
+/* Flags for I365_IOCTL */
+#define I365_IOCTL_MASK(map)	(0x0F << (map<<2))
+#define I365_IOCTL_WAIT(map)	(0x08 << (map<<2))
+#define I365_IOCTL_0WS(map)	(0x04 << (map<<2))
+#define I365_IOCTL_IOCS16(map)	(0x02 << (map<<2))
+#define I365_IOCTL_16BIT(map)	(0x01 << (map<<2))
+
+/* Flags for I365_GENCTL */
+#define I365_CTL_16DELAY	0x01
+#define I365_CTL_RESET		0x02
+#define I365_CTL_GPI_ENA	0x04
+#define I365_CTL_GPI_CTL	0x08
+#define I365_CTL_RESUME		0x10
+#define I365_CTL_SW_IRQ		0x20
+
+/* Flags for I365_GBLCTL */
+#define I365_GBL_PWRDOWN	0x01
+#define I365_GBL_CSC_LEV	0x02
+#define I365_GBL_WRBACK		0x04
+#define I365_GBL_IRQ_0_LEV	0x08
+#define I365_GBL_IRQ_1_LEV	0x10
+
+/* Flags for memory window registers */
+#define I365_MEM_16BIT	0x8000	/* In memory start high byte */
+#define I365_MEM_0WS	0x4000
+#define I365_MEM_WS1	0x8000	/* In memory stop high byte */
+#define I365_MEM_WS0	0x4000
+#define I365_MEM_WRPROT	0x8000	/* In offset high byte */
+#define I365_MEM_REG	0x4000
+
+#define I365_REG(slot, reg)	(((slot) << 6) + reg)
+
+#endif /* _LINUX_I82365_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/o2micro.h linux/drivers/pcmcia/o2micro.h
--- v2.3.16/linux/drivers/pcmcia/o2micro.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/o2micro.h	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,98 @@
+/*
+ * o2micro.h 1.10 1999/09/03 16:43:35
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_O2MICRO_H
+#define _LINUX_O2MICRO_H
+
+#ifndef PCI_VENDOR_ID_O2
+#define PCI_VENDOR_ID_O2		0x1217
+#endif
+#ifndef PCI_DEVICE_ID_O2_6729
+#define PCI_DEVICE_ID_O2_6729		0x6729
+#endif
+#ifndef PCI_DEVICE_ID_O2_6730
+#define PCI_DEVICE_ID_O2_6730		0x673a
+#endif
+#ifndef PCI_DEVICE_ID_O2_6832
+#define PCI_DEVICE_ID_O2_6832		0x6832
+#endif
+#ifndef PCI_DEVICE_ID_O2_6836
+#define PCI_DEVICE_ID_O2_6836		0x6836
+#endif
+
+#define O2_MODE_A		0x38
+#define O2_MODE_A_2		0x26	/* For 6833B, 6860C */
+#define  O2_MODE_A_CD_PULSE	0x04
+#define  O2_MODE_A_SUSP_EDGE	0x08
+#define  O2_MODE_A_HOST_SUSP	0x10
+#define  O2_MODE_A_PWRCHIP	0x60
+#define  O2_MODE_A_QUIET	0x80
+
+#define O2_MODE_B		0x39
+#define O2_MODE_B_2		0x2e	/* For 6833B, 6860C */
+#define  O2_MODE_B_IDENT	0x03
+#define  O2_MODE_B_ID_BSTEP	0x00
+#define  O2_MODE_B_ID_CSTEP	0x01
+#define  O2_MODE_B_ID_O2	0x02
+#define  O2_MODE_B_VS1		0x04
+#define  O2_MODE_B_VS2		0x08
+#define  O2_MODE_B_IRQ15_RI	0x80
+
+#define O2_MODE_C		0x3a
+#define  O2_MODE_C_DREQ_MASK	0x03
+#define  O2_MODE_C_DREQ_INPACK	0x01
+#define  O2_MODE_C_DREQ_WP	0x02
+#define  O2_MODE_C_DREQ_BVD2	0x03
+#define  O2_MODE_C_ZVIDEO	0x08
+
+#define O2_MODE_D		0x3b
+#define  O2_MODE_D_IRQ_MODE	0x03
+#define  O2_MODE_D_SKT_ACTV	0x20
+#define  O2_MODE_D_PCI_FIFO	0x40	/* for OZ6729, OZ6730 */
+#define  O2_MODE_D_W97_IRQ	0x40	/* for OZ6832 */
+#define  O2_MODE_D_ISA_IRQ	0x80
+
+#define O2_MHPG_DMA		0x3c
+#define  O2_MHPG_CHANNEL	0x07
+#define  O2_MHPG_CINT_ENA	0x08
+#define  O2_MHPG_CSC_ENA	0x10
+
+#define O2_FIFO_ENA		0x3d
+#define  O2_FIFO_ZVIDEO_3	0x08
+#define  O2_FIFO_PCI_FIFO	0x10
+#define  O2_FIFO_POSTWR		0x40
+#define  O2_FIFO_BUFFER		0x80
+
+#define O2_MODE_E		0x3e
+#define  O2_MODE_E_MHPG_DMA	0x01
+#define  O2_MODE_E_SPKR_OUT	0x02
+#define  O2_MODE_E_LED_OUT	0x08
+#define  O2_MODE_E_SKTA_ACTV	0x10
+
+#endif /* _LINUX_O2MICRO_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/ricoh.h linux/drivers/pcmcia/ricoh.h
--- v2.3.16/linux/drivers/pcmcia/ricoh.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/ricoh.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,132 @@
+/*
+ * ricoh.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_RICOH_H
+#define _LINUX_RICOH_H
+
+#define RF5C_MODE_CTL		0x1f	/* Mode control */
+#define RF5C_PWR_CTL		0x2f	/* Mixed voltage control */
+#define RF5C_CHIP_ID		0x3a	/* Chip identification */
+#define RF5C_MODE_CTL_3		0x3b	/* Mode control 3 */
+
+/* I/O window address offset */
+#define RF5C_IO_OFF(w)		(0x36+((w)<<1))
+
+/* Flags for RF5C_MODE_CTL */
+#define RF5C_MODE_ATA		0x01	/* ATA mode */
+#define RF5C_MODE_LED_ENA	0x02	/* IRQ 12 is LED */
+#define RF5C_MODE_CA21		0x04
+#define RF5C_MODE_CA22		0x08
+#define RF5C_MODE_CA23		0x10
+#define RF5C_MODE_CA24		0x20
+#define RF5C_MODE_CA25		0x40
+#define RF5C_MODE_3STATE_BIT7	0x80
+
+/* Flags for RF5C_PWR_CTL */
+#define RF5C_PWR_VCC_3V		0x01
+#define RF5C_PWR_IREQ_HIGH	0x02
+#define RF5C_PWR_INPACK_ENA	0x04
+#define RF5C_PWR_5V_DET		0x08
+#define RF5C_PWR_TC_SEL		0x10	/* Terminal Count: irq 11 or 15 */
+#define RF5C_PWR_DREQ_LOW	0x20
+#define RF5C_PWR_DREQ_OFF	0x00	/* DREQ steering control */
+#define RF5C_PWR_DREQ_INPACK	0x40
+#define RF5C_PWR_DREQ_SPKR	0x80
+#define RF5C_PWR_DREQ_IOIS16	0xc0
+
+/* Values for RF5C_CHIP_ID */
+#define RF5C_CHIP_RF5C296	0x32
+#define RF5C_CHIP_RF5C396	0xb2
+
+/* Flags for RF5C_MODE_CTL_3 */
+#define RF5C_MCTL3_DISABLE	0x01	/* Disable PCMCIA interface */
+#define RF5C_MCTL3_DMA_ENA	0x02
+
+/* Register definitions for Ricoh PCI-to-CardBus bridges */
+
+#ifndef PCI_VENDOR_ID_RICOH
+#define PCI_VENDOR_ID_RICOH		0x1180
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C465
+#define PCI_DEVICE_ID_RICOH_RL5C465	0x0465
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C466
+#define PCI_DEVICE_ID_RICOH_RL5C466	0x0466
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C475
+#define PCI_DEVICE_ID_RICOH_RL5C475	0x0475
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C476
+#define PCI_DEVICE_ID_RICOH_RL5C476	0x0476
+#endif
+#ifndef PCI_DEVICE_ID_RICOH_RL5C478
+#define PCI_DEVICE_ID_RICOH_RL5C478	0x0478
+#endif
+
+/* Extra bits in CB_BRIDGE_CONTROL */
+#define RL5C46X_BCR_3E0_ENA		0x0800
+#define RL5C46X_BCR_3E2_ENA		0x1000
+
+/* Misc Control Register */
+#define RL5C4XX_MISC			0x0082	/* 16 bit */
+#define  RL5C4XX_MISC_HW_SUSPEND_ENA	0x0002
+#define  RL5C4XX_MISC_VCCEN_POL		0x0100
+#define  RL5C4XX_MISC_VPPEN_POL		0x0200
+#define  RL5C46X_MISC_SUSPEND		0x0001
+#define  RL5C46X_MISC_PWR_SAVE_2	0x0004
+#define  RL5C46X_MISC_IFACE_BUSY	0x0008
+#define  RL5C46X_MISC_B_LOCK		0x0010
+#define  RL5C46X_MISC_A_LOCK		0x0020
+#define  RL5C46X_MISC_PCI_LOCK		0x0040
+#define  RL5C47X_MISC_IFACE_BUSY	0x0004
+#define  RL5C47X_MISC_PCI_INT_MASK	0x0018
+#define  RL5C47X_MISC_PCI_INT_DIS	0x0020
+#define  RL5C47X_MISC_SUBSYS_WR		0x0040
+#define  RL5C47X_MISC_SRIRQ_ENA		0x0080
+#define  RL5C47X_MISC_5V_DISABLE	0x0400
+#define  RL5C47X_MISC_LED_POL		0x0800
+
+/* 16-bit Interface Control Register */
+#define RL5C4XX_16BIT_CTL		0x0084	/* 16 bit */
+#define  RL5C4XX_16CTL_IO_TIMING	0x0100
+#define  RL5C4XX_16CTL_MEM_TIMING	0x0200
+#define  RL5C46X_16CTL_LEVEL_1		0x0010
+#define  RL5C46X_16CTL_LEVEL_2		0x0020
+
+/* 16-bit IO and memory timing registers */
+#define RL5C4XX_16BIT_IO_0		0x0088	/* 16 bit */
+#define RL5C4XX_16BIT_MEM_0		0x0088	/* 16 bit */
+#define  RL5C4XX_SETUP_MASK		0x0007
+#define  RL5C4XX_SETUP_SHIFT		0
+#define  RL5C4XX_CMD_MASK		0x01f0
+#define  RL5C4XX_CMD_SHIFT		4
+#define  RL5C4XX_HOLD_MASK		0x1c00
+#define  RL5C4XX_HOLD_SHIFT		10
+
+#endif /* _LINUX_RICOH_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/rsrc_mgr.c linux/drivers/pcmcia/rsrc_mgr.c
--- v2.3.16/linux/drivers/pcmcia/rsrc_mgr.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/rsrc_mgr.c	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,802 @@
+/*======================================================================
+
+    Resource management routines
+
+    rsrc_mgr.c 1.70 1999/09/07 15:19:32
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#define __NO_VERSION__
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Should we probe resources for conflicts? */
+static int probe_mem = 1;
+MODULE_PARM(probe_mem, "i");
+#ifdef CONFIG_ISA
+static int probe_io = 1;
+static int mem_limit = 0x10000;
+MODULE_PARM(probe_io, "i");
+MODULE_PARM(mem_limit, "i");
+#endif
+
+/*======================================================================
+
+    The resource_map_t structures are used to track what resources are
+    available for allocation for PC Card devices.
+
+======================================================================*/
+
+typedef struct resource_map_t {
+    u_long			base, num;
+    struct resource_map_t	*next;
+} resource_map_t;
+
+/* Memory resource database */
+static resource_map_t mem_db = { 0, 0, &mem_db };
+
+/* IO port resource database */
+static resource_map_t io_db = { 0, 0, &io_db };
+
+#ifdef CONFIG_ISA
+
+typedef struct irq_info_t {
+    u_int			Attributes;
+    int				time_share, dyn_share;
+    struct socket_info_t	*Socket;
+} irq_info_t;
+
+/* Table of IRQ assignments */
+static irq_info_t irq_table[NR_IRQS] = { { 0, 0, 0 }, /* etc */ };
+
+#endif
+
+static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED;
+
+/*======================================================================
+
+    Linux resource management extensions
+    
+======================================================================*/
+
+typedef struct resource_entry_t {
+    u_long			base, num;
+    char			*name;
+    struct resource_entry_t	*next;
+} resource_entry_t;
+
+/* Ordered linked lists of allocated IO and memory blocks */
+static resource_entry_t io_list = { 0, 0, NULL, NULL };
+#ifndef HAVE_MEMRESERVE
+static resource_entry_t mem_list = { 0, 0, NULL, NULL };
+#endif
+
+static resource_entry_t *find_gap(resource_entry_t *root,
+				  resource_entry_t *entry)
+{
+    resource_entry_t *p;
+    
+    if (entry->base > entry->base+entry->num-1)
+	return NULL;
+    for (p = root; ; p = p->next) {
+	if ((p != root) && (p->base+p->num-1 >= entry->base)) {
+	    p = NULL;
+	    break;
+	}
+	if ((p->next == NULL) ||
+	    (p->next->base > entry->base+entry->num-1))
+	    break;
+    }
+    return p;
+}
+
+static int register_my_resource(resource_entry_t *list,
+				u_long base, u_long num, char *name)
+{
+    u_long flags;
+    resource_entry_t *p, *entry;
+
+    entry = kmalloc(sizeof(resource_entry_t), GFP_ATOMIC);
+    entry->base = base;
+    entry->num = num;
+    entry->name = name;
+
+    spin_lock_irqsave(&rsrc_lock, flags);
+    p = find_gap(list, entry);
+    if (p == NULL) {
+	spin_unlock_irqrestore(&rsrc_lock, flags);
+	kfree(entry);
+	return -EBUSY;
+    }
+    entry->next = p->next;
+    p->next = entry;
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return 0;
+}
+
+static void release_my_resource(resource_entry_t *list,
+				u_long base, u_long num)
+{
+    u_long flags;
+    resource_entry_t *p, *q;
+
+    spin_lock_irqsave(&rsrc_lock, flags);
+    for (p = list; ; p = q) {
+	q = p->next;
+	if (q == NULL) break;
+	if ((q->base == base) && (q->num == num)) {
+	    p->next = q->next;
+	    kfree(q);
+	    spin_unlock_irqrestore(&rsrc_lock, flags);
+	    return;
+	}
+    }
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return;
+}
+
+static int check_my_resource(resource_entry_t *list,
+			     u_long base, u_long num)
+{
+    if (register_my_resource(list, base, num, NULL) != 0)
+	return -EBUSY;
+    release_my_resource(list, base, num);
+    return 0;
+}
+
+int check_io_region(u_long base, u_long num)
+{
+    return check_my_resource(&io_list, base, num);
+}
+void request_io_region(u_long base, u_long num, char *name)
+{
+    register_my_resource(&io_list, base, num, name);
+}
+void release_io_region(u_long base, u_long num)
+{
+    release_my_resource(&io_list, base, num);
+}
+#ifdef CONFIG_PROC_FS
+int proc_read_io(char *buf, char **start, off_t pos,
+		 int count, int *eof, void *data)
+{
+    resource_entry_t *r;
+    u_long flags;
+    char *p = buf;
+    
+    spin_lock_irqsave(&rsrc_lock, flags);
+    for (r = io_list.next; r; r = r->next)
+	p += sprintf(p, "%04lx-%04lx : %s\n", r->base,
+		     r->base+r->num-1, r->name);
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return (p - buf);
+}
+#endif
+
+
+/*======================================================================
+
+    These manage the internal databases of available resources.
+    
+======================================================================*/
+
+static int add_interval(resource_map_t *map, u_long base, u_long num)
+{
+    resource_map_t *p, *q;
+
+    for (p = map; ; p = p->next) {
+	if ((p != map) && (p->base+p->num-1 >= base))
+	    return -1;
+	if ((p->next == map) || (p->next->base > base+num-1))
+	    break;
+    }
+    q = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+    q->base = base; q->num = num;
+    q->next = p->next; p->next = q;
+    return 0;
+} /* add_interval */
+
+/*====================================================================*/
+
+static int sub_interval(resource_map_t *map, u_long base, u_long num)
+{
+    resource_map_t *p, *q;
+
+    for (p = map; ; p = q) {
+	q = p->next;
+	if (q == map)
+	    break;
+	if ((q->base+q->num > base) && (base+num > q->base)) {
+	    if (q->base >= base) {
+		if (q->base+q->num <= base+num) {
+		    /* Delete whole block */
+		    p->next = q->next;
+		    kfree(q);
+		    /* don't advance the pointer yet */
+		    q = p;
+		} else {
+		    /* Cut off bit from the front */
+		    q->num = q->base + q->num - base - num;
+		    q->base = base + num;
+		}
+	    } else if (q->base+q->num <= base+num) {
+		/* Cut off bit from the end */
+		q->num = base - q->base;
+	    } else {
+		/* Split the block into two pieces */
+		p = kmalloc(sizeof(resource_map_t), GFP_KERNEL);
+		p->base = base+num;
+		p->num = q->base+q->num - p->base;
+		q->num = base - q->base;
+		p->next = q->next ; q->next = p;
+	    }
+	}
+    }
+    return 0;
+} /* sub_interval */
+
+/*======================================================================
+
+    These routines examine a region of IO or memory addresses to
+    determine what ranges might be genuinely available.
+    
+======================================================================*/
+
+#ifdef CONFIG_ISA
+static void do_io_probe(ioaddr_t base, ioaddr_t num)
+{
+    
+    ioaddr_t i, j, bad, any;
+    u_char *b, hole, most;
+    
+    printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
+	   base, base+num-1);
+    
+    /* First, what does a floating port look like? */
+    b = kmalloc(256, GFP_KERNEL);
+    memset(b, 0, 256);
+    for (i = base, most = 0; i < base+num; i += 8) {
+	if (check_region(i, 8) || check_io_region(i, 8))
+	    continue;
+	hole = inb(i);
+	for (j = 1; j < 8; j++)
+	    if (inb(i+j) != hole) break;
+	if ((j == 8) && (++b[hole] > b[most]))
+	    most = hole;
+	if (b[most] == 127) break;
+    }
+    kfree(b);
+
+    bad = any = 0;
+    for (i = base; i < base+num; i += 8) {
+	if (check_region(i, 8) || check_io_region(i, 8))
+	    continue;
+	for (j = 0; j < 8; j++)
+	    if (inb(i+j) != most) break;
+	if (j < 8) {
+	    if (!any)
+		printk(" excluding");
+	    if (!bad)
+		bad = any = i;
+	} else {
+	    if (bad) {
+		sub_interval(&io_db, bad, i-bad);
+		printk(" %#04x-%#04x", bad, i-1);
+		bad = 0;
+	    }
+	}
+    }
+    if (bad) {
+	if ((num > 16) && (bad == base) && (i == base+num)) {
+	    printk(" nothing: probe failed.\n");
+	    return;
+	} else {
+	    sub_interval(&io_db, bad, i-bad);
+	    printk(" %#04x-%#04x", bad, i-1);
+	}
+    }
+    
+    printk(any ? "\n" : " clean.\n");
+}
+#endif
+
+/*======================================================================
+
+    The memory probe.  If the memory list includes a 64K-aligned block
+    below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+    least mem_limit free space, we quit.
+    
+======================================================================*/
+
+static int do_mem_probe(u_long base, u_long num,
+			int (*is_valid)(u_long), int (*do_cksum)(u_long))
+{
+    u_long i, j, bad, fail, step;
+
+    printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
+	   base, base+num-1);
+
+    bad = fail = 0;
+    step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+    for (i = base; i < base+num; i = j + step) {
+	if (!fail) {	
+	    for (j = i; j < base+num; j += step)
+		if ((check_mem_region(j, step) == 0) && is_valid(j))
+		    break;
+	    fail = ((i == base) && (j == base+num));
+	}
+	if (fail) {
+	    for (j = i; j < base+num; j += 2*step)
+		if ((check_mem_region(j, 2*step) == 0) &&
+		    do_cksum(j) && do_cksum(j+step))
+		    break;
+	}
+	if (i != j) {
+	    if (!bad) printk(" excluding");
+	    printk(" %#05lx-%#05lx", i, j-1);
+	    sub_interval(&mem_db, i, j-i);
+	    bad += j-i;
+	}
+    }
+    printk(bad ? "\n" : " clean.\n");
+
+    return (num - bad);
+}
+
+#ifdef CONFIG_ISA
+
+static u_long inv_probe(int (*is_valid)(u_long),
+			int (*do_cksum)(u_long),
+			resource_map_t *m)
+{
+    u_long ok;
+    if (m == &mem_db)
+	return 0;
+    ok = inv_probe(is_valid, do_cksum, m->next);
+    if (ok) {
+	if (m->base >= 0x100000)
+	    sub_interval(&mem_db, m->base, m->num);
+	return ok;
+    }
+    if (m->base < 0x100000)
+	return 0;
+    return do_mem_probe(m->base, m->num, is_valid, do_cksum);
+}
+
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+		  int force_low)
+{
+    resource_map_t *m, *n;
+    static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
+    static int hi = 0, lo = 0;
+    u_long b, i, ok = 0;
+    
+    if (!probe_mem) return;
+    /* We do up to four passes through the list */
+    if (!force_low) {
+	if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next) > 0))
+	    return;
+	printk(KERN_NOTICE "cs: warning: no high memory space "
+	       "available!\n");
+    }
+    if (lo++) return;
+    for (m = mem_db.next; m != &mem_db; m = n) {
+	n = m->next;
+	/* Only probe < 1 MB */
+	if (m->base >= 0x100000) continue;
+	if ((m->base | m->num) & 0xffff) {
+	    ok += do_mem_probe(m->base, m->num, is_valid, do_cksum);
+	    continue;
+	}
+	/* Special probe for 64K-aligned block */
+	for (i = 0; i < 4; i++) {
+	    b = order[i] << 12;
+	    if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) {
+		if (ok >= mem_limit)
+		    sub_interval(&mem_db, b, 0x10000);
+		else
+		    ok += do_mem_probe(b, 0x10000, is_valid, do_cksum);
+	    }
+	}
+    }
+}
+
+#else /* CONFIG_ISA */
+
+void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+		  int force_low)
+{
+    resource_map_t *m;
+    static int done = 0;
+    
+    if (!probe_mem || done++)
+	return;
+    for (m = mem_db.next; m != &mem_db; m = m->next)
+	if (do_mem_probe(m->base, m->num, is_valid, do_cksum))
+	    return;
+}
+
+#endif /* CONFIG_ISA */
+
+/*======================================================================
+
+    These find ranges of I/O ports or memory addresses that are not
+    currently allocated by other devices.
+    
+======================================================================*/
+
+int find_io_region(ioaddr_t *base, ioaddr_t num, char *name)
+{
+    ioaddr_t align;
+    resource_map_t *m;
+    
+    if (*base != 0) {
+	for (m = io_db.next; m != &io_db; m = m->next) {
+	    if ((*base >= m->base) && (*base+num <= m->base+m->num)) {
+		if (check_region(*base, num) ||
+		    check_io_region(*base, num)) {
+		    return -1;
+		} else {
+		    request_region(*base, num, name);
+		    return 0;
+		}
+	    }
+	}
+	return -1;
+    }
+    
+    for (align = 1; align < num; align *= 2) ;
+
+    for (m = io_db.next; m != &io_db; m = m->next) {
+	for (*base = (m->base + align - 1) & (~(align-1));
+	     *base+align <= m->base + m->num;
+	     *base += align)
+	    if ((check_region(*base, num) == 0) &&
+		(check_io_region(*base, num) == 0)) {
+		request_region(*base, num, name);
+		return 0;
+	    }
+    }
+    return -1;
+} /* find_io_region */
+
+int find_mem_region(u_long *base, u_long num, char *name,
+		    u_long align, int force_low)
+{
+    resource_map_t *m;
+
+    if (*base != 0) {
+	for (m = mem_db.next; m != &mem_db; m = m->next) {
+	    if ((*base >= m->base) && (*base+num <= m->base+m->num))
+		if (check_mem_region(*base, num) == 0) {
+		    request_mem_region(*base, num, name);
+		    return 0;
+		}
+	}
+	return -1;
+    }
+    
+    while (1) {
+	for (m = mem_db.next; m != &mem_db; m = m->next) {
+	    /* first pass >1MB, second pass <1MB */
+	    if ((force_low != 0) ^ (m->base < 0x100000)) continue;
+	    for (*base = (m->base + align - 1) & (~(align-1));
+		 *base+num <= m->base+m->num; *base += align)
+		if (check_mem_region(*base, num) == 0) {
+		    request_mem_region(*base, num, name);
+		    return 0;
+		}
+	}
+	if (force_low) break;
+	force_low++;
+    }
+    return -1;
+} /* find_mem_region */
+
+/*======================================================================
+
+    This checks to see if an interrupt is available, with support
+    for interrupt sharing.  We don't support reserving interrupts
+    yet.  If the interrupt is available, we allocate it.
+    
+======================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void fake_irq(int i, void *d, struct pt_regs *r) { }
+static inline int check_irq(int irq)
+{
+    if (request_irq(irq, fake_irq, 0, "bogus", NULL) != 0)
+	return -1;
+    free_irq(irq, NULL);
+    return 0;
+}
+
+int try_irq(u_int Attributes, int irq, int specific)
+{
+    irq_info_t *info = &irq_table[irq];
+    if (info->Attributes & RES_ALLOCATED) {
+	switch (Attributes & IRQ_TYPE) {
+	case IRQ_TYPE_EXCLUSIVE:
+	    return CS_IN_USE;
+	case IRQ_TYPE_TIME:
+	    if ((info->Attributes & RES_IRQ_TYPE)
+		!= RES_IRQ_TYPE_TIME)
+		return CS_IN_USE;
+	    if (Attributes & IRQ_FIRST_SHARED)
+		return CS_BAD_ATTRIBUTE;
+	    info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
+	    info->time_share++;
+	    break;
+	case IRQ_TYPE_DYNAMIC_SHARING:
+	    if ((info->Attributes & RES_IRQ_TYPE)
+		!= RES_IRQ_TYPE_DYNAMIC)
+		return CS_IN_USE;
+	    if (Attributes & IRQ_FIRST_SHARED)
+		return CS_BAD_ATTRIBUTE;
+	    info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
+	    info->dyn_share++;
+	    break;
+	}
+    } else {
+	if ((info->Attributes & RES_RESERVED) && !specific)
+	    return CS_IN_USE;
+	if (check_irq(irq) != 0)
+	    return CS_IN_USE;
+	switch (Attributes & IRQ_TYPE) {
+	case IRQ_TYPE_EXCLUSIVE:
+	    info->Attributes |= RES_ALLOCATED;
+	    break;
+	case IRQ_TYPE_TIME:
+	    if (!(Attributes & IRQ_FIRST_SHARED))
+		return CS_BAD_ATTRIBUTE;
+	    info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED;
+	    info->time_share = 1;
+	    break;
+	case IRQ_TYPE_DYNAMIC_SHARING:
+	    if (!(Attributes & IRQ_FIRST_SHARED))
+		return CS_BAD_ATTRIBUTE;
+	    info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED;
+	    info->dyn_share = 1;
+	    break;
+	}
+    }
+    return 0;
+} /* try_irq */
+
+#endif
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+void undo_irq(u_int Attributes, int irq)
+{
+    irq_info_t *info;
+
+    info = &irq_table[irq];
+    switch (Attributes & IRQ_TYPE) {
+    case IRQ_TYPE_EXCLUSIVE:
+	info->Attributes &= RES_RESERVED;
+	break;
+    case IRQ_TYPE_TIME:
+	info->time_share--;
+	if (info->time_share == 0)
+	    info->Attributes &= RES_RESERVED;
+	break;
+    case IRQ_TYPE_DYNAMIC_SHARING:
+	info->dyn_share--;
+	if (info->dyn_share == 0)
+	    info->Attributes &= RES_RESERVED;
+	break;
+    }
+}
+
+#endif
+
+/*======================================================================
+
+    The various adjust_* calls form the external interface to the
+    resource database.
+    
+======================================================================*/
+
+static int adjust_memory(adjust_t *adj)
+{
+    u_long base, num;
+    int i;
+
+    base = adj->resource.memory.Base;
+    num = adj->resource.memory.Size;
+    if ((num == 0) || (base+num-1 < base))
+	return CS_BAD_SIZE;
+
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+	if (add_interval(&mem_db, base, num) != 0)
+	    return CS_IN_USE;
+	break;
+    case REMOVE_MANAGED_RESOURCE:
+	sub_interval(&mem_db, base, num);
+	for (i = 0; i < sockets; i++) {
+	    release_cis_mem(socket_table[i]);
+#ifdef CONFIG_CARDBUS
+	    cb_release_cis_mem(socket_table[i]);
+#endif
+	}
+	break;
+    default:
+	return CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+    
+    return CS_SUCCESS;
+} /* adjust_mem */
+
+/*====================================================================*/
+
+static int adjust_io(adjust_t *adj)
+{
+    int base, num;
+    
+    base = adj->resource.io.BasePort;
+    num = adj->resource.io.NumPorts;
+    if ((base < 0) || (base > 0xffff))
+	return CS_BAD_BASE;
+    if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
+	return CS_BAD_SIZE;
+
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+	if (add_interval(&io_db, base, num) != 0)
+	    return CS_IN_USE;
+#ifdef CONFIG_ISA
+	if (probe_io)
+	    do_io_probe(base, num);
+#endif
+	break;
+    case REMOVE_MANAGED_RESOURCE:
+	sub_interval(&io_db, base, num);
+	break;
+    default:
+	return CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+
+    return CS_SUCCESS;
+} /* adjust_io */
+
+/*====================================================================*/
+
+static int adjust_irq(adjust_t *adj)
+{
+#ifdef CONFIG_ISA
+    int irq;
+    irq_info_t *info;
+    
+    irq = adj->resource.irq.IRQ;
+    if ((irq < 0) || (irq > 15))
+	return CS_BAD_IRQ;
+    info = &irq_table[irq];
+    
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+	if (info->Attributes & RES_REMOVED)
+	    info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED);
+	else
+	    if (adj->Attributes & RES_ALLOCATED)
+		return CS_IN_USE;
+	if (adj->Attributes & RES_RESERVED)
+	    info->Attributes |= RES_RESERVED;
+	else
+	    info->Attributes &= ~RES_RESERVED;
+	break;
+    case REMOVE_MANAGED_RESOURCE:
+	if (info->Attributes & RES_REMOVED)
+	    return 0;
+	if (info->Attributes & RES_ALLOCATED)
+	    return CS_IN_USE;
+	info->Attributes |= RES_ALLOCATED|RES_REMOVED;
+	info->Attributes &= ~RES_RESERVED;
+	break;
+    default:
+	return CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+#endif
+    return CS_SUCCESS;
+} /* adjust_irq */
+
+/*====================================================================*/
+
+int adjust_resource_info(client_handle_t handle, adjust_t *adj)
+{
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+    
+    switch (adj->Resource) {
+    case RES_MEMORY_RANGE:
+	return adjust_memory(adj);
+	break;
+    case RES_IO_RANGE:
+	return adjust_io(adj);
+	break;
+    case RES_IRQ:
+	return adjust_irq(adj);
+	break;
+    }
+    return CS_UNSUPPORTED_FUNCTION;
+} /* adjust_resource_info */
+
+/*====================================================================*/
+
+void release_resource_db(void)
+{
+    resource_map_t *p, *q;
+    resource_entry_t *u, *v;
+    
+    for (p = mem_db.next; p != &mem_db; p = q) {
+	q = p->next;
+	kfree(p);
+    }
+    for (p = io_db.next; p != &io_db; p = q) {
+	q = p->next;
+	kfree(p);
+    }
+    for (u = io_list.next; u; u = v) {
+	v = u->next;
+	kfree(u);
+    }
+#ifndef HAVE_MEMRESERVE
+    for (u = mem_list.next; u; u = v) {
+	v = u->next;
+	kfree(u);
+    }
+#endif
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/rsrc_mgr.h linux/drivers/pcmcia/rsrc_mgr.h
--- v2.3.16/linux/drivers/pcmcia/rsrc_mgr.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/rsrc_mgr.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,39 @@
+/*
+ * rsrc_mgr.h 1.18 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _RSRC_MGR_H
+#define _RSRC_MGR_H
+
+#ifdef __BEOS__
+int check_resource(int type, u_long base, u_long num);
+int register_resource(int type, u_long base, u_long num);
+int release_resource(int type, u_long base, u_long num);
+#endif
+
+#endif	/* _RSRC_MGR_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/smc34c90.h linux/drivers/pcmcia/smc34c90.h
--- v2.3.16/linux/drivers/pcmcia/smc34c90.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/smc34c90.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,52 @@
+/*
+ * smc34c90.h 1.6 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_SMC34C90_H
+#define _LINUX_SMC34C90_H
+
+#ifndef PCI_VENDOR_ID_SMC
+#define PCI_VENDOR_ID_SMC		0x10b3
+#endif
+
+#ifndef PCI_DEVICE_ID_SMC_34C90
+#define PCI_DEVICE_ID_SMC_34C90		0xb106
+#endif
+
+/* Register definitions for SMC 34C90 PCI-to-CardBus bridge */
+
+/* EEPROM Information Register */
+#define SMC34C90_EEINFO			0x0088
+#define SMC34C90_EEINFO_ONE_SOCKET	0x0001
+#define SMC34C90_EEINFO_5V_ONLY		0x0002
+#define SMC34C90_EEINFO_ISA_IRQ		0x0004
+#define SMC34C90_EEINFO_ZV_PORT		0x0008
+#define SMC34C90_EEINFO_RING		0x0010
+#define SMC34C90_EEINFO_LED		0x0020
+
+#endif /* _LINUX_SMC34C90_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/tcic.c linux/drivers/pcmcia/tcic.c
--- v2.3.16/linux/drivers/pcmcia/tcic.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/tcic.c	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,979 @@
+/*======================================================================
+
+    Device driver for Databook TCIC-2 PCMCIA controller
+
+    tcic.c 1.105 1999/09/06 06:55:14
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include "tcic.h"
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"tcic.c 1.105 1999/09/06 06:55:14 (David Hinds)";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The base port address of the TCIC-2 chip */
+static int tcic_base = TCIC_BASE;
+
+/* Specify a socket number to ignore */
+static int ignore = -1;
+
+/* Probe for safe interrupts? */
+static int do_scan = 1;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xffff;
+static int irq_list[16] = { -1 };
+
+/* The card status change interrupt -- 0 means autoselect */
+static int cs_irq = 0;
+
+/* Poll status interval -- 0 means default to interrupt */
+static int poll_interval = 0;
+
+/* Delay for card status double-checking */
+static int poll_quick = HZ/20;
+
+/* CCLK external clock time, in nanoseconds.  70 ns = 14.31818 MHz */
+static int cycle_time = 70;
+
+MODULE_PARM(tcic_base, "i");
+MODULE_PARM(ignore, "i");
+MODULE_PARM(do_scan, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-16i");
+MODULE_PARM(cs_irq, "i");
+MODULE_PARM(poll_interval, "i");
+MODULE_PARM(poll_quick, "i");
+MODULE_PARM(cycle_time, "i");
+
+/*====================================================================*/
+
+static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs);
+static void tcic_timer(u_long data);
+static int tcic_service(u_int sock, u_int cmd, void *arg);
+
+typedef struct socket_info_t {
+    u_short	psock;
+    void	(*handler)(void *info, u_int events);
+    void	*info;
+    u_char	last_sstat;
+    u_char	id;
+} socket_info_t;
+
+static struct timer_list poll_timer;
+static int tcic_timer_pending = 0;
+
+static int sockets;
+static socket_info_t socket_table[2];
+
+static socket_cap_t tcic_cap = {
+    /* only 16-bit cards, memory windows must be size-aligned */
+    SS_CAP_PCCARD | SS_CAP_MEM_ALIGN,
+    0x4cf8,		/* irq 14, 11, 10, 7, 6, 5, 4, 3 */
+    0x1000,		/* 4K minimum window size */
+    0, 0		/* No PCI or CardBus support */
+};
+
+/*====================================================================*/
+
+/* Trick when selecting interrupts: the TCIC sktirq pin is supposed
+   to map to irq 11, but is coded as 0 or 1 in the irq registers. */
+#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
+
+#ifdef PCMCIA_DEBUG_X
+static u_char tcic_getb(u_char reg)
+{
+    u_char val = inb(tcic_base+reg);
+    printk(KERN_DEBUG "tcic_getb(%#x) = %#x\n", tcic_base+reg, val);
+    return val;
+}
+
+static u_short tcic_getw(u_char reg)
+{
+    u_short val = inw(tcic_base+reg);
+    printk(KERN_DEBUG "tcic_getw(%#x) = %#x\n", tcic_base+reg, val);
+    return val;
+}
+
+static void tcic_setb(u_char reg, u_char data)
+{
+    printk(KERN_DEBUG "tcic_setb(%#x, %#x)\n", tcic_base+reg, data);
+    outb(data, tcic_base+reg);
+}
+
+static void tcic_setw(u_char reg, u_short data)
+{
+    printk(KERN_DEBUG "tcic_setw(%#x, %#x)\n", tcic_base+reg, data);
+    outw(data, tcic_base+reg);
+}
+#else
+#define tcic_getb(reg) inb(tcic_base+reg)
+#define tcic_getw(reg) inw(tcic_base+reg)
+#define tcic_setb(reg, data) outb(data, tcic_base+reg)
+#define tcic_setw(reg, data) outw(data, tcic_base+reg)
+#endif
+
+static void tcic_setl(u_char reg, u_int data)
+{
+#ifdef PCMCIA_DEBUG_X
+    printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
+#endif
+    outw(data & 0xffff, tcic_base+reg);
+    outw(data >> 16, tcic_base+reg+2);
+}
+
+static u_char tcic_aux_getb(u_short reg)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    return tcic_getb(TCIC_AUX);
+}
+
+static void tcic_aux_setb(u_short reg, u_char data)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    tcic_setb(TCIC_AUX, data);
+}
+
+static u_short tcic_aux_getw(u_short reg)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    return tcic_getw(TCIC_AUX);
+}
+
+static void tcic_aux_setw(u_short reg, u_short data)
+{
+    u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(TCIC_MODE, mode);
+    tcic_setw(TCIC_AUX, data);
+}
+
+/*====================================================================*/
+
+/* Time conversion functions */
+
+static int to_cycles(int ns)
+{
+    if (ns < 14)
+	return 0;
+    else
+	return 2*(ns-14)/cycle_time;
+}
+
+static int to_ns(int cycles)
+{
+    return (cycles*cycle_time)/2 + 14;
+}
+
+/*====================================================================*/
+
+static volatile u_int irq_hits;
+
+static void irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+    irq_hits++;
+}
+
+static u_int try_irq(int irq)
+{
+    u_short cfg;
+
+    irq_hits = 0;
+    if (request_irq(irq, irq_count, 0, "irq scan", NULL) != 0)
+	return -1;
+    mdelay(10);
+    if (irq_hits) {
+	free_irq(irq, NULL);
+	return -1;
+    }
+
+    /* Generate one interrupt */
+    cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00;
+    tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq));
+    tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH);
+    tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
+
+    udelay(1000);
+    free_irq(irq, NULL);
+
+    /* Turn off interrupts */
+    tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
+    while (tcic_getb(TCIC_ICSR))
+	tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM);
+    tcic_aux_setw(TCIC_AUX_SYSCFG, cfg);
+    
+    return (irq_hits != 1);
+}
+
+static u_int irq_scan(u_int mask0)
+{
+    u_int mask1;
+    int i;
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    /* Don't probe level-triggered interrupts -- reserved for PCI */
+    int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8);
+    if (level_mask)
+	mask0 &= ~level_mask;
+#endif
+
+    mask1 = 0;
+    if (do_scan) {
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (try_irq(i) == 0))
+		mask1 |= (1 << i);
+	for (i = 0; i < 16; i++)
+	    if ((mask1 & (1 << i)) && (try_irq(i) != 0)) {
+		mask1 ^= (1 << i);
+	    }
+    }
+    
+    if (mask1) {
+	printk("scanned");
+    } else {
+	/* Fallback: just find interrupts that aren't in use */
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) &&
+		(request_irq(i, irq_count, 0, "x", NULL) == 0)) {
+		mask1 |= (1 << i);
+		free_irq(i, NULL);
+	    }
+	printk("default");
+    }
+    
+    printk(") = ");
+    for (i = 0; i < 16; i++)
+	if (mask1 & (1<<i))
+	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+    printk(" ");
+    
+    return mask1;
+}
+
+/*======================================================================
+
+    See if a card is present, powered up, in IO mode, and already
+    bound to a (non-PCMCIA) Linux driver.
+
+    We make an exception for cards that look like serial devices.
+    
+======================================================================*/
+
+static int is_active(int s)
+{
+    u_short scf1, ioctl, base, num;
+    u_char pwr, sstat;
+    u_int addr;
+    
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF1(s));
+    scf1 = tcic_getw(TCIC_DATA);
+    pwr = tcic_getb(TCIC_PWR);
+    sstat = tcic_getb(TCIC_SSTAT);
+    addr = TCIC_IWIN(s, 0);
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    ioctl = tcic_getw(TCIC_DATA);
+
+    if (ioctl & TCIC_ICTL_TINY)
+	num = 1;
+    else {
+	num = (base ^ (base-1));
+	base = base & (base-1);
+    }
+
+    if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
+	(scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
+	(check_region(base, num) != 0) && ((base & 0xfeef) != 0x02e8))
+	return 1;
+    else
+	return 0;
+}
+
+/*======================================================================
+
+    This returns the revision code for the specified socket.
+    
+======================================================================*/
+
+static int get_tcic_id(void)
+{
+    u_short id;
+    
+    tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG);
+    id = tcic_aux_getw(TCIC_AUX_ILOCK);
+    id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
+    tcic_aux_setw(TCIC_AUX_TEST, 0);
+    return id;
+}
+
+/*====================================================================*/
+
+int tcic_init(void)
+{
+    int i, sock;
+    u_int mask, scan;
+
+    DEBUG(0, "%s\n", version);
+    
+    printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
+    sock = 0;
+
+    if (check_region(tcic_base, 16) == 0) {
+	tcic_setw(TCIC_ADDR, 0);
+	if (tcic_getw(TCIC_ADDR) == 0) {
+	    tcic_setw(TCIC_ADDR, 0xc3a5);
+	    if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+	}
+	if (sock == 0) {
+	    /* See if resetting the controller does any good */
+	    tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
+	    tcic_setb(TCIC_SCTRL, 0);
+	    tcic_setw(TCIC_ADDR, 0);
+	    if (tcic_getw(TCIC_ADDR) == 0) {
+		tcic_setw(TCIC_ADDR, 0xc3a5);
+		if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
+	    }
+	}
+    } else
+	printk("could not allocate ports, ");
+
+    if (sock == 0) {
+	printk("not found.\n");
+	return -ENODEV;
+    }
+
+    request_region(tcic_base, 16, "tcic-2");
+
+    sockets = 0;
+    for (i = 0; i < sock; i++) {
+	if ((i == ignore) || is_active(i)) continue;
+	socket_table[sockets].psock = i;
+	socket_table[sockets].handler = NULL;
+	socket_table[sockets].info = NULL;
+	socket_table[sockets].id = get_tcic_id();
+	sockets++;
+    }
+
+    switch (socket_table[0].id) {
+    case TCIC_ID_DB86082:
+	printk("DB86082"); break;
+    case TCIC_ID_DB86082A:
+	printk("DB86082A"); break;
+    case TCIC_ID_DB86084:
+	printk("DB86084"); break;
+    case TCIC_ID_DB86084A:
+	printk("DB86084A"); break;
+    case TCIC_ID_DB86072:
+	printk("DB86072"); break;
+    case TCIC_ID_DB86184:
+	printk("DB86184"); break;
+    case TCIC_ID_DB86082B:
+	printk("DB86082B"); break;
+    default:
+	printk("Unknown ID 0x%02x", socket_table[0].id);
+    }
+    
+    /* Set up polling */
+    poll_timer.function = &tcic_timer;
+    poll_timer.data = 0;
+    poll_timer.prev = poll_timer.next = NULL;
+
+    /* Build interrupt mask */
+    printk(", %d sockets\n" KERN_INFO "  irq list (", sockets);
+    if (irq_list[0] == -1)
+	mask = irq_mask;
+    else
+	for (i = mask = 0; i < 16; i++)
+	    mask |= (1<<irq_list[i]);
+    mask &= tcic_cap.irq_mask;
+
+    /* Scan interrupts */
+    mask = irq_scan(mask);
+    tcic_cap.irq_mask = mask;
+    
+    /* Check for only two interrupts available */
+    scan = (mask & (mask-1));
+    if (((scan & (scan-1)) == 0) && (poll_interval == 0))
+	poll_interval = HZ;
+    
+    if (poll_interval == 0) {
+	/* Avoid irq 12 unless it is explicitly requested */
+	u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
+	for (i = 15; i > 0; i--)
+	    if ((cs_mask & (1 << i)) &&
+		(request_irq(i, tcic_interrupt, 0, "tcic", NULL) == 0))
+		break;
+	cs_irq = i;
+	if (cs_irq == 0) poll_interval = HZ;
+    }
+    
+    if (tcic_cap.irq_mask & (1 << 11))
+	printk("sktirq is irq 11, ");
+    if (cs_irq != 0)
+	printk("status change on irq %d\n", cs_irq);
+    else
+	printk("polled status, interval = %d ms\n",
+	       poll_interval * 1000 / HZ);
+    
+    for (i = 0; i < sockets; i++) {
+	tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);
+	socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);
+    }
+    
+    /* jump start interrupt handler, if needed */
+    tcic_interrupt(0, NULL, NULL);
+
+    if (register_ss_entry(sockets, &tcic_service) != 0) {
+	printk(KERN_NOTICE "tcic: register_ss_entry() failed\n");
+	release_region(tcic_base, 16);
+	if (cs_irq != 0)
+	    free_irq(cs_irq, NULL);
+	return -ENODEV;
+    }
+
+    return 0;
+    
+} /* tcic_init */
+
+/*====================================================================*/
+
+static void tcic_finish(void)
+{
+    u_long flags;
+    unregister_ss_entry(&tcic_service);
+    save_flags(flags);
+    cli();
+    if (cs_irq != 0) {
+	tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
+	free_irq(cs_irq, NULL);
+    }
+    if (tcic_timer_pending)
+	del_timer(&poll_timer);
+    restore_flags(flags);
+    release_region(tcic_base, 16);
+} /* tcic_finish */
+
+/*====================================================================*/
+
+static void tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+    int i, quick = 0;
+    u_char latch, sstat;
+    u_short psock;
+    u_int events;
+    static volatile int active = 0;
+
+    if (active) {
+	printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");
+	return;
+    } else
+	active = 1;
+
+    DEBUG(2, "tcic: tcic_interrupt()\n");
+    
+    for (i = 0; i < sockets; i++) {
+	psock = socket_table[i].psock;
+	tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+		  | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+	sstat = tcic_getb(TCIC_SSTAT);
+	latch = sstat ^ socket_table[psock].last_sstat;
+	socket_table[i].last_sstat = sstat;
+	if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {
+	    tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);
+	    quick = 1;
+	}
+	if ((latch == 0) || (socket_table[psock].handler == NULL))
+	    continue;
+	events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+	events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+	if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+	    events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+	} else {
+	    events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;
+	    events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+	    events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+	}
+	if (events)
+	    socket_table[i].handler(socket_table[i].info, events);
+    }
+
+    /* Schedule next poll, if needed */
+    if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {
+	poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
+	add_timer(&poll_timer);
+	tcic_timer_pending = 1;
+    }
+    active = 0;
+    
+    DEBUG(2, "tcic: interrupt done\n");
+    
+} /* tcic_interrupt */
+
+static void tcic_timer(u_long data)
+{
+    DEBUG(2, "tcic: tcic_timer()\n");
+    tcic_timer_pending = 0;
+    tcic_interrupt(0, NULL, NULL);
+} /* tcic_timer */
+
+/*====================================================================*/
+
+static int tcic_register_callback(u_short lsock, ss_callback_t *call)
+{
+    if (call == NULL) {
+	socket_table[lsock].handler = NULL;
+	MOD_DEC_USE_COUNT;
+    } else {
+	MOD_INC_USE_COUNT;
+	socket_table[lsock].handler = call->handler;
+	socket_table[lsock].info = call->info;
+    }
+    return 0;
+} /* tcic_register_callback */
+
+/*====================================================================*/
+
+static int tcic_get_status(u_short lsock, u_int *value)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_char reg;
+
+    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+    reg = tcic_getb(TCIC_SSTAT);
+    *value  = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;
+    *value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
+    if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
+	*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
+    } else {
+	*value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;
+	*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
+	*value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
+    }
+    reg = tcic_getb(TCIC_PWR);
+    if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
+	*value |= SS_POWERON;
+    DEBUG(1, "tcic: GetStatus(%d) = %#2.2x\n", lsock, *value);
+    return 0;
+} /* tcic_get_status */
+  
+/*====================================================================*/
+
+static int tcic_inquire_socket(u_short lsock, socket_cap_t *cap)
+{
+    *cap = tcic_cap;
+    return 0;
+} /* tcic_inquire_socket */
+
+/*====================================================================*/
+
+static int tcic_get_socket(u_short lsock, socket_state_t *state)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_char reg;
+    u_short scf1, scf2;
+    
+    tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF1(psock));
+    scf1 = tcic_getw(TCIC_DATA);
+    state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0;
+    state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0;
+    state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0;
+    if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA)
+	state->flags |= SS_OUTPUT_ENA;
+    state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK;
+    if (state->io_irq == 1) state->io_irq = 11;
+
+    reg = tcic_getb(TCIC_PWR);
+    state->Vcc = state->Vpp = 0;
+    if (reg & TCIC_PWR_VCC(psock)) {
+	if (reg & TCIC_PWR_VPP(psock))
+	    state->Vcc = 50;
+	else
+	    state->Vcc = state->Vpp = 50;
+    } else {
+	if (reg & TCIC_PWR_VPP(psock)) {
+	    state->Vcc = 50;
+	    state->Vpp = 120;
+	}
+    }
+    reg = tcic_aux_getb(TCIC_AUX_ILOCK);
+    state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0;
+
+    /* Card status change interrupt mask */
+    tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+    scf2 = tcic_getw(TCIC_DATA);
+    state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT;
+    if (state->flags & SS_IOCARD) {
+	state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG;
+    } else {
+	state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD;
+	state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN;
+	state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY;
+    }
+
+    DEBUG(1, "tcic: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    return 0;
+} /* tcic_get_socket */
+
+/*====================================================================*/
+
+static int tcic_set_socket(u_short lsock, socket_state_t *state)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_char reg;
+    u_short scf1, scf2;
+
+    DEBUG(1, "tcic: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
+
+    reg = tcic_getb(TCIC_PWR);
+    reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));
+
+    if (state->Vcc == 50) {
+	switch (state->Vpp) {
+	case 0:   reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;
+	case 50:  reg |= TCIC_PWR_VCC(psock); break;
+	case 120: reg |= TCIC_PWR_VPP(psock); break;
+	default:  return -EINVAL;
+	}
+    } else if (state->Vcc != 0)
+	return -EINVAL;
+
+    if (reg != tcic_getb(TCIC_PWR))
+	tcic_setb(TCIC_PWR, reg);
+
+    reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;
+    if (state->flags & SS_OUTPUT_ENA) {
+	tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);
+	reg |= TCIC_ILOCK_CRESENA;
+    } else
+	tcic_setb(TCIC_SCTRL, 0);
+    if (state->flags & SS_RESET)
+	reg |= TCIC_ILOCK_CRESET;
+    tcic_aux_setb(TCIC_AUX_ILOCK, reg);
+    
+    tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));
+    scf1 = TCIC_SCF1_FINPACK;
+    scf1 |= TCIC_IRQ(state->io_irq);
+    if (state->flags & SS_IOCARD) {
+	scf1 |= TCIC_SCF1_IOSTS;
+	if (state->flags & SS_SPKR_ENA)
+	    scf1 |= TCIC_SCF1_SPKR;
+	if (state->flags & SS_DMA_MODE)
+	    scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;
+    }
+    tcic_setw(TCIC_DATA, scf1);
+
+    /* Some general setup stuff, and configure status interrupt */
+    reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);
+    tcic_aux_setb(TCIC_AUX_WCTL, reg);
+    tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|
+		  TCIC_IRQ(cs_irq));
+    
+    /* Card status change interrupt mask */
+    tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
+    scf2 = TCIC_SCF2_MALL;
+    if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;
+    if (state->flags & SS_IOCARD) {
+	if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;
+    } else {
+	if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;
+	if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;
+	if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;
+    }
+    tcic_setw(TCIC_DATA, scf2);
+    /* For the ISA bus, the irq should be active-high totem-pole */
+    tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);
+
+    return 0;
+} /* tcic_set_socket */
+  
+/*====================================================================*/
+
+static int tcic_get_io_map(u_short lsock, struct pccard_io_map *io)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_short base, ioctl;
+    u_int addr;
+    
+    if (io->map > 1) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_IWIN(psock, io->map);
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    ioctl = tcic_getw(TCIC_DATA);
+
+    if (ioctl & TCIC_ICTL_TINY)
+	io->start = io->stop = base;
+    else {
+	io->start = base & (base-1);
+	io->stop = io->start + (base ^ (base-1));
+    }
+    io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK);
+    io->flags  = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0;
+    switch (ioctl & TCIC_ICTL_BW_MASK) {
+    case TCIC_ICTL_BW_DYN:
+	io->flags |= MAP_AUTOSZ; break;
+    case TCIC_ICTL_BW_16:
+	io->flags |= MAP_16BIT; break;
+    default:
+	break;
+    }
+    DEBUG(1, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, "
+	  "%#4.4x-%#4.4x\n", lsock, io->map, io->flags,
+	  io->speed, io->start, io->stop);
+    return 0;
+} /* tcic_get_io_map */
+
+/*====================================================================*/
+
+static int tcic_set_io_map(u_short lsock, struct pccard_io_map *io)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_int addr;
+    u_short base, len, ioctl;
+    
+    DEBUG(1, "tcic: SetIOMap(%d, %d, %#2.2x, %d ns, "
+	  "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+	  io->speed, io->start, io->stop);
+    if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
+	(io->stop < io->start)) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_IWIN(psock, io->map);
+
+    base = io->start; len = io->stop - io->start;
+    /* Check to see that len+1 is power of two, etc */
+    if ((len & (len+1)) || (base & len)) return -EINVAL;
+    base |= (len+1)>>1;
+    tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
+    tcic_setw(TCIC_DATA, base);
+    
+    ioctl  = (psock << TCIC_ICTL_SS_SHFT);
+    ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;
+    ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;
+    ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;
+    if (!(io->flags & MAP_AUTOSZ)) {
+	ioctl |= TCIC_ICTL_QUIET;
+	ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;
+    }
+    tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
+    tcic_setw(TCIC_DATA, ioctl);
+    
+    return 0;
+} /* tcic_set_io_map */
+
+/*====================================================================*/
+
+static int tcic_get_mem_map(u_short lsock, struct pccard_mem_map *mem)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_short addr, ctl;
+    u_long base, mmap;
+    
+    if (mem->map > 3) return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_MWIN(psock, mem->map);
+    
+    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    if (base & TCIC_MBASE_4K_BIT) {
+	mem->sys_start = base & TCIC_MBASE_HA_MASK;
+	mem->sys_stop = mem->sys_start;
+    } else {
+	base &= TCIC_MBASE_HA_MASK;
+	mem->sys_start = (base & (base-1));
+	mem->sys_stop = mem->sys_start + (base ^ (base-1));
+    }
+    mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT;
+    mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff;
+    
+    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+    mmap = tcic_getw(TCIC_DATA);
+    mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0;
+    mmap &= TCIC_MMAP_CA_MASK;
+    mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT);
+    mem->card_start &= 0x3ffffff;
+    
+    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+    ctl = tcic_getw(TCIC_DATA);
+    mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0;
+    mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT;
+    mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0;
+    mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK);
+    
+    DEBUG(1, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, "
+	  "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags,
+	  mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+    return 0;
+} /* tcic_get_mem_map */
+
+/*====================================================================*/
+  
+static int tcic_set_mem_map(u_short lsock, struct pccard_mem_map *mem)
+{
+    u_short psock = socket_table[lsock].psock;
+    u_short addr, ctl;
+    u_long base, len, mmap;
+
+    DEBUG(1, "tcic: SetMemMap(%d, %d, %#2.2x, %d ns, "
+	  "%#5.5lx-%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+	  mem->speed, mem->sys_start, mem->sys_stop, mem->card_start);
+    if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
+	(mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff) ||
+	(mem->sys_start > mem->sys_stop) || (mem->speed > 1000))
+	return -EINVAL;
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
+    addr = TCIC_MWIN(psock, mem->map);
+
+    base = mem->sys_start; len = mem->sys_stop - mem->sys_start;
+    if ((len & (len+1)) || (base & len)) return -EINVAL;
+    if (len == 0x0fff)
+	base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
+    else
+	base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
+    tcic_setw(TCIC_DATA, base);
+    
+    mmap = mem->card_start - mem->sys_start;
+    mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
+    if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
+    tcic_setw(TCIC_DATA, mmap);
+
+    ctl  = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);
+    ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;
+    ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;
+    ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;
+    ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;
+    tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
+    tcic_setw(TCIC_DATA, ctl);
+    
+    return 0;
+} /* tcic_set_mem_map */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(u_short, void *);
+    
+static subfn_t service_table[] = {
+    (subfn_t)&tcic_register_callback,
+    (subfn_t)&tcic_inquire_socket,
+    (subfn_t)&tcic_get_status,
+    (subfn_t)&tcic_get_socket,
+    (subfn_t)&tcic_set_socket,
+    (subfn_t)&tcic_get_io_map,
+    (subfn_t)&tcic_set_io_map,
+    (subfn_t)&tcic_get_mem_map,
+    (subfn_t)&tcic_set_mem_map,
+};
+
+#define NFUNC (sizeof(service_table)/sizeof(subfn_t))
+
+static int tcic_service(u_int lsock, u_int cmd, void *arg)
+{
+    int err;
+
+    DEBUG(2, "tcic_service(%d, %d, 0x%p)\n", lsock, cmd, arg);
+
+    if (cmd < NFUNC)
+	err = service_table[cmd](lsock, arg);
+    else
+	err = -EINVAL;
+
+    return err;
+} /* tcic_service */
+
+/*====================================================================*/
+
+int pcmcia_tcic_init(void)
+{
+    servinfo_t serv;
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "tcic: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    return tcic_init();
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return pcmcia_tcic_init();
+}
+
+void cleanup_module(void)
+{
+    tcic_finish();
+}
+#endif
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/tcic.h linux/drivers/pcmcia/tcic.h
--- v2.3.16/linux/drivers/pcmcia/tcic.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/tcic.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,266 @@
+/*
+ * tcic.h 1.12 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TCIC_H
+#define _LINUX_TCIC_H
+
+#define TCIC_BASE		0x240
+
+/* offsets of registers from TCIC_BASE */
+#define TCIC_DATA		0x00
+#define TCIC_ADDR		0x02
+#define TCIC_SCTRL		0x06
+#define TCIC_SSTAT		0x07
+#define TCIC_MODE		0x08
+#define TCIC_PWR		0x09
+#define TCIC_EDC		0x0A
+#define TCIC_ICSR		0x0C
+#define TCIC_IENA		0x0D
+#define TCIC_AUX		0x0E
+
+#define TCIC_SS_SHFT		12
+#define TCIC_SS_MASK		0x7000
+
+/* Flags for TCIC_ADDR */
+#define TCIC_ADR2_REG		0x8000
+#define TCIC_ADR2_INDREG	0x0800
+
+#define TCIC_ADDR_REG		0x80000000
+#define TCIC_ADDR_SS_SHFT	(TCIC_SS_SHFT+16)
+#define TCIC_ADDR_SS_MASK	(TCIC_SS_MASK<<16)
+#define TCIC_ADDR_INDREG	0x08000000
+#define TCIC_ADDR_IO		0x04000000
+#define TCIC_ADDR_MASK		0x03ffffff
+
+/* Flags for TCIC_SCTRL */
+#define TCIC_SCTRL_ENA		0x01
+#define TCIC_SCTRL_INCMODE	0x18
+#define TCIC_SCTRL_INCMODE_HOLD	0x00
+#define TCIC_SCTRL_INCMODE_WORD	0x08
+#define TCIC_SCTRL_INCMODE_REG	0x10
+#define TCIC_SCTRL_INCMODE_AUTO	0x18
+#define TCIC_SCTRL_EDCSUM	0x20
+#define TCIC_SCTRL_RESET	0x80
+
+/* Flags for TCIC_SSTAT */
+#define TCIC_SSTAT_6US		0x01
+#define TCIC_SSTAT_10US		0x02
+#define TCIC_SSTAT_PROGTIME	0x04
+#define TCIC_SSTAT_LBAT1	0x08
+#define TCIC_SSTAT_LBAT2	0x10
+#define TCIC_SSTAT_RDY		0x20	/* Inverted */
+#define TCIC_SSTAT_WP		0x40
+#define TCIC_SSTAT_CD		0x80	/* Card detect */
+
+/* Flags for TCIC_MODE */
+#define TCIC_MODE_PGMMASK	0x1f
+#define TCIC_MODE_NORMAL	0x00
+#define TCIC_MODE_PGMWR		0x01
+#define TCIC_MODE_PGMRD		0x02
+#define TCIC_MODE_PGMCE		0x04
+#define TCIC_MODE_PGMDBW	0x08
+#define TCIC_MODE_PGMWORD	0x10
+#define TCIC_MODE_AUXSEL_MASK	0xe0
+
+/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
+#define TCIC_AUX_TCTL		(0<<5)
+#define TCIC_AUX_PCTL		(1<<5)
+#define TCIC_AUX_WCTL		(2<<5)
+#define TCIC_AUX_EXTERN		(3<<5)
+#define TCIC_AUX_PDATA		(4<<5)
+#define TCIC_AUX_SYSCFG		(5<<5)
+#define TCIC_AUX_ILOCK		(6<<5)
+#define TCIC_AUX_TEST		(7<<5)
+
+/* Flags for TCIC_PWR */
+#define TCIC_PWR_VCC(sock)	(0x01<<(sock))
+#define TCIC_PWR_VCC_MASK	0x03
+#define TCIC_PWR_VPP(sock)	(0x08<<(sock))
+#define TCIC_PWR_VPP_MASK	0x18
+#define TCIC_PWR_CLIMENA	0x40
+#define TCIC_PWR_CLIMSTAT	0x80
+
+/* Flags for TCIC_ICSR */
+#define TCIC_ICSR_CLEAR		0x01
+#define TCIC_ICSR_SET		0x02
+#define TCIC_ICSR_JAM		(TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
+#define TCIC_ICSR_STOPCPU	0x04
+#define TCIC_ICSR_ILOCK		0x08
+#define TCIC_ICSR_PROGTIME	0x10
+#define TCIC_ICSR_ERR		0x20
+#define TCIC_ICSR_CDCHG		0x40
+#define TCIC_ICSR_IOCHK		0x80
+
+/* Flags for TCIC_IENA */
+#define TCIC_IENA_CFG_MASK	0x03
+#define TCIC_IENA_CFG_OFF	0x00	/* disabled */
+#define TCIC_IENA_CFG_OD	0x01	/* active low, open drain */
+#define TCIC_IENA_CFG_LOW	0x02	/* active low, totem pole */
+#define TCIC_IENA_CFG_HIGH	0x03	/* active high, totem pole */
+#define TCIC_IENA_ILOCK		0x08
+#define TCIC_IENA_PROGTIME	0x10
+#define TCIC_IENA_ERR		0x20	/* overcurrent or iochk */
+#define TCIC_IENA_CDCHG		0x40
+
+/* Flags for TCIC_AUX_WCTL */
+#define TCIC_WAIT_COUNT_MASK	0x001f
+#define TCIC_WAIT_ASYNC		0x0020
+#define TCIC_WAIT_SENSE		0x0040
+#define TCIC_WAIT_SRC		0x0080
+#define TCIC_WCTL_WR		0x0100
+#define TCIC_WCTL_RD		0x0200
+#define TCIC_WCTL_CE		0x0400
+#define TCIC_WCTL_LLBAT1	0x0800
+#define TCIC_WCTL_LLBAT2	0x1000
+#define TCIC_WCTL_LRDY		0x2000
+#define TCIC_WCTL_LWP		0x4000
+#define TCIC_WCTL_LCD		0x8000
+
+/* Flags for TCIC_AUX_SYSCFG */
+#define TCIC_SYSCFG_IRQ_MASK	0x000f
+#define TCIC_SYSCFG_MCSFULL	0x0010
+#define TCIC_SYSCFG_IO1723	0x0020
+#define TCIC_SYSCFG_MCSXB	0x0040
+#define TCIC_SYSCFG_ICSXB	0x0080
+#define TCIC_SYSCFG_NOPDN	0x0100
+#define TCIC_SYSCFG_MPSEL_SHFT	9
+#define TCIC_SYSCFG_MPSEL_MASK	0x0e00
+#define TCIC_SYSCFG_MPSENSE	0x2000
+#define TCIC_SYSCFG_AUTOBUSY	0x4000
+#define TCIC_SYSCFG_ACC		0x8000
+
+#define TCIC_ILOCK_OUT		0x01
+#define TCIC_ILOCK_SENSE	0x02
+#define TCIC_ILOCK_CRESET	0x04
+#define TCIC_ILOCK_CRESENA	0x08
+#define TCIC_ILOCK_CWAIT	0x10
+#define TCIC_ILOCK_CWAITSNS	0x20
+#define TCIC_ILOCK_HOLD_MASK	0xc0
+#define TCIC_ILOCK_HOLD_CCLK	0xc0
+
+#define TCIC_ILOCKTEST_ID_SH	8
+#define TCIC_ILOCKTEST_ID_MASK	0x7f00
+#define TCIC_ILOCKTEST_MCIC_1	0x8000
+
+#define TCIC_ID_DB86082		0x02
+#define TCIC_ID_DB86082A	0x03
+#define TCIC_ID_DB86084		0x04
+#define TCIC_ID_DB86084A	0x08
+#define TCIC_ID_DB86072		0x15
+#define TCIC_ID_DB86184		0x14
+#define TCIC_ID_DB86082B	0x17
+
+#define TCIC_TEST_DIAG		0x8000
+
+/*
+ * Indirectly addressed registers
+ */
+
+#define TCIC_SCF1(sock)	((sock)<<3)
+#define TCIC_SCF2(sock) (((sock)<<3)+2)
+
+/* Flags for SCF1 */
+#define TCIC_SCF1_IRQ_MASK	0x000f
+#define TCIC_SCF1_IRQ_OFF	0x0000
+#define TCIC_SCF1_IRQOC		0x0010
+#define TCIC_SCF1_PCVT		0x0020
+#define TCIC_SCF1_IRDY		0x0040
+#define TCIC_SCF1_ATA		0x0080
+#define TCIC_SCF1_DMA_SHIFT	8
+#define TCIC_SCF1_DMA_MASK	0x0700
+#define TCIC_SCF1_DMA_OFF	0
+#define TCIC_SCF1_DREQ2		2
+#define TCIC_SCF1_IOSTS		0x0800
+#define TCIC_SCF1_SPKR		0x1000
+#define TCIC_SCF1_FINPACK	0x2000
+#define TCIC_SCF1_DELWR		0x4000
+#define TCIC_SCF1_HD7IDE	0x8000
+
+/* Flags for SCF2 */
+#define TCIC_SCF2_RI		0x0001
+#define TCIC_SCF2_IDBR		0x0002
+#define TCIC_SCF2_MDBR		0x0004
+#define TCIC_SCF2_MLBAT1	0x0008
+#define TCIC_SCF2_MLBAT2	0x0010
+#define TCIC_SCF2_MRDY		0x0020
+#define TCIC_SCF2_MWP		0x0040
+#define TCIC_SCF2_MCD		0x0080
+#define TCIC_SCF2_MALL		0x00f8
+
+/* Indirect addresses for memory window registers */
+#define TCIC_MWIN(sock,map)	(0x100+(((map)+((sock)<<2))<<3))
+#define TCIC_MBASE_X		2
+#define TCIC_MMAP_X		4
+#define TCIC_MCTL_X		6
+
+#define TCIC_MBASE_4K_BIT	0x4000
+#define TCIC_MBASE_HA_SHFT	12
+#define TCIC_MBASE_HA_MASK	0x0fff
+
+#define TCIC_MMAP_REG		0x8000
+#define TCIC_MMAP_CA_SHFT	12
+#define TCIC_MMAP_CA_MASK	0x3fff
+
+#define TCIC_MCTL_WSCNT_MASK	0x001f
+#define TCIC_MCTL_WCLK		0x0020
+#define TCIC_MCTL_WCLK_CCLK	0x0000
+#define TCIC_MCTL_WCLK_BCLK	0x0020
+#define TCIC_MCTL_QUIET		0x0040
+#define TCIC_MCTL_WP		0x0080
+#define TCIC_MCTL_ACC		0x0100
+#define TCIC_MCTL_KE		0x0200
+#define TCIC_MCTL_EDC		0x0400
+#define TCIC_MCTL_B8		0x0800
+#define TCIC_MCTL_SS_SHFT	TCIC_SS_SHFT
+#define TCIC_MCTL_SS_MASK	TCIC_SS_MASK
+#define TCIC_MCTL_ENA		0x8000
+
+/* Indirect addresses for I/O window registers */
+#define TCIC_IWIN(sock,map)	(0x200+(((map)+((sock)<<1))<<2))
+#define TCIC_IBASE_X		0
+#define TCIC_ICTL_X		2
+
+#define TCIC_ICTL_WSCNT_MASK	TCIC_MCTL_WSCNT_MASK
+#define TCIC_ICTL_QUIET		TCIC_MCTL_QUIET
+#define TCIC_ICTL_1K		0x0080
+#define TCIC_ICTL_PASS16	0x0100
+#define TCIC_ICTL_ACC		TCIC_MCTL_ACC
+#define TCIC_ICTL_TINY		0x0200
+#define TCIC_ICTL_B16		0x0400
+#define TCIC_ICTL_B8		TCIC_MCTL_B8
+#define TCIC_ICTL_BW_MASK	(TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_BW_DYN	0
+#define TCIC_ICTL_BW_8		TCIC_ICTL_B8
+#define TCIC_ICTL_BW_16		TCIC_ICTL_B16
+#define TCIC_ICTL_BW_ATA	(TCIC_ICTL_B16|TCIC_ICTL_B8)
+#define TCIC_ICTL_SS_SHFT	TCIC_SS_SHFT
+#define TCIC_ICTL_SS_MASK	TCIC_SS_MASK
+#define TCIC_ICTL_ENA		TCIC_MCTL_ENA
+
+#endif /* _LINUX_TCIC_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/ti113x.h linux/drivers/pcmcia/ti113x.h
--- v2.3.16/linux/drivers/pcmcia/ti113x.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/ti113x.h	Tue Sep  7 11:03:10 1999
@@ -0,0 +1,180 @@
+/*
+ * ti113x.h 1.15 1999/09/03 16:43:35
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_TI113X_H
+#define _LINUX_TI113X_H
+
+#ifndef PCI_VENDOR_ID_TI
+#define PCI_VENDOR_ID_TI		0x104c
+#endif
+
+#ifndef PCI_DEVICE_ID_TI_1130
+#define PCI_DEVICE_ID_TI_1130		0xac12
+#endif
+#ifndef PCI_DEVICE_ID_TI_1131
+#define PCI_DEVICE_ID_TI_1131		0xac15
+#endif
+#ifndef PCI_DEVICE_ID_TI_1031
+#define PCI_DEVICE_ID_TI_1031		0xac13
+#endif
+#ifndef PCI_DEVICE_ID_TI_1250A
+#define PCI_DEVICE_ID_TI_1250A		0xac16
+#endif
+#ifndef PCI_DEVICE_ID_TI_1220
+#define PCI_DEVICE_ID_TI_1220		0xac17
+#endif
+#ifndef PCI_DEVICE_ID_TI_1221
+#define PCI_DEVICE_ID_TI_1221		0xac19
+#endif
+#ifndef PCI_DEVICE_ID_TI_1210
+#define PCI_DEVICE_ID_TI_1210		0xac1a
+#endif
+#ifndef PCI_DEVICE_ID_TI_1450
+#define PCI_DEVICE_ID_TI_1450		0xac1b
+#endif
+#ifndef PCI_DEVICE_ID_TI_1225
+#define PCI_DEVICE_ID_TI_1225		0xac1c
+#endif
+#ifndef PCI_DEVICE_ID_TI_1251A
+#define PCI_DEVICE_ID_TI_1251A		0xac1d
+#endif
+#ifndef PCI_DEVICE_ID_TI_1211
+#define PCI_DEVICE_ID_TI_1211		0xac1e
+#endif
+#ifndef PCI_DEVICE_ID_TI_1251B
+#define PCI_DEVICE_ID_TI_1251B		0xac1f
+#endif
+#ifndef PCI_DEVICE_ID_TI_1420
+#define PCI_DEVICE_ID_TI_1420		0xac51
+#endif
+
+/* Register definitions for TI 113X PCI-to-CardBus bridges */
+
+/* System Control Register */
+#define TI113X_SYSTEM_CONTROL		0x0080	/* 32 bit */
+#define  TI113X_SCR_SMIROUTE		0x04000000
+#define  TI113X_SCR_SMISTATUS		0x02000000
+#define  TI113X_SCR_SMIENB		0x01000000
+#define  TI113X_SCR_VCCPROT		0x00200000
+#define  TI113X_SCR_REDUCEZV		0x00100000
+#define  TI113X_SCR_CDREQEN		0x00080000
+#define  TI113X_SCR_CDMACHAN		0x00070000
+#define  TI113X_SCR_SOCACTIVE		0x00002000
+#define  TI113X_SCR_PWRSTREAM		0x00000800
+#define  TI113X_SCR_DELAYUP		0x00000400
+#define  TI113X_SCR_DELAYDOWN		0x00000200
+#define  TI113X_SCR_INTERROGATE		0x00000100
+#define  TI113X_SCR_CLKRUN_SEL		0x00000080
+#define  TI113X_SCR_PWRSAVINGS		0x00000040
+#define  TI113X_SCR_SUBSYSRW		0x00000020
+#define  TI113X_SCR_CB_DPAR		0x00000010
+#define  TI113X_SCR_CDMA_EN		0x00000008
+#define  TI113X_SCR_ASYNC_IRQ		0x00000004
+#define  TI113X_SCR_KEEPCLK		0x00000002
+#define  TI113X_SCR_CLKRUN_ENA		0x00000001  
+
+#define  TI122X_SCR_SER_STEP		0xc0000000
+#define  TI122X_SCR_INTRTIE		0x20000000
+#define  TI122X_SCR_CBRSVD		0x00400000
+#define  TI122X_SCR_MRBURSTDN		0x00008000
+#define  TI122X_SCR_MRBURSTUP		0x00004000
+#define  TI122X_SCR_RIMUX		0x00000001
+
+/* Multimedia Control Register */
+#define TI1250_MULTIMEDIA_CTL		0x0084	/* 8 bit */
+#define  TI1250_MMC_ZVOUTEN		0x80
+#define  TI1250_MMC_PORTSEL		0x40
+#define  TI1250_MMC_ZVEN1		0x02
+#define  TI1250_MMC_ZVEN0		0x01
+
+#define TI1250_GENERAL_STATUS		0x0085	/* 8 bit */
+#define TI1250_GPIO0_CONTROL		0x0088	/* 8 bit */
+#define TI1250_GPIO1_CONTROL		0x0089	/* 8 bit */
+#define TI1250_GPIO2_CONTROL		0x008a	/* 8 bit */
+#define TI1250_GPIO3_CONTROL		0x008b	/* 8 bit */
+#define TI122X_IRQMUX			0x008c	/* 32 bit */
+
+/* Retry Status Register */
+#define TI113X_RETRY_STATUS		0x0090	/* 8 bit */
+#define  TI113X_RSR_PCIRETRY		0x80
+#define  TI113X_RSR_CBRETRY		0x40
+#define  TI113X_RSR_TEXP_CBB		0x20
+#define  TI113X_RSR_MEXP_CBB		0x10
+#define  TI113X_RSR_TEXP_CBA		0x08
+#define  TI113X_RSR_MEXP_CBA		0x04
+#define  TI113X_RSR_TEXP_PCI		0x02
+#define  TI113X_RSR_MEXP_PCI		0x01
+
+/* Card Control Register */
+#define TI113X_CARD_CONTROL		0x0091	/* 8 bit */
+#define  TI113X_CCR_RIENB		0x80
+#define  TI113X_CCR_ZVENABLE		0x40
+#define  TI113X_CCR_PCI_IRQ_ENA		0x20
+#define  TI113X_CCR_PCI_IREQ		0x10
+#define  TI113X_CCR_PCI_CSC		0x08
+#define  TI113X_CCR_SPKROUTEN		0x02
+#define  TI113X_CCR_IFG			0x01
+
+#define  TI1220_CCR_PORT_SEL		0x20
+#define  TI122X_CCR_AUD2MUX		0x04
+
+/* Device Control Register */
+#define TI113X_DEVICE_CONTROL		0x0092	/* 8 bit */
+#define  TI113X_DCR_5V_FORCE		0x40
+#define  TI113X_DCR_3V_FORCE		0x20
+#define  TI113X_DCR_IMODE_MASK		0x06
+#define  TI113X_DCR_IMODE_ISA		0x02
+#define  TI113X_DCR_IMODE_SERIAL	0x04
+
+#define  TI12XX_DCR_IMODE_PCI_ONLY	0x00
+#define  TI12XX_DCR_IMODE_ALL_SERIAL	0x06
+
+/* Buffer Control Register */
+#define TI113X_BUFFER_CONTROL		0x0093	/* 8 bit */
+#define  TI113X_BCR_CB_READ_DEPTH	0x08
+#define  TI113X_BCR_CB_WRITE_DEPTH	0x04
+#define  TI113X_BCR_PCI_READ_DEPTH	0x02
+#define  TI113X_BCR_PCI_WRITE_DEPTH	0x01
+
+/* Diagnostic Register */
+#define TI1250_DIAGNOSTIC		0x0093	/* 8 bit */
+#define  TI1250_DIAG_TRUE_VALUE		0x80
+#define  TI1250_DIAG_PCI_IREQ		0x40
+#define  TI1250_DIAG_PCI_CSC		0x20
+#define  TI1250_DIAG_ASYNC_CSC		0x01
+
+/* DMA Registers */
+#define TI113X_DMA_0			0x0094	/* 32 bit */
+#define TI113X_DMA_1			0x0098	/* 32 bit */
+
+/* ExCA IO offset registers */
+#define TI113X_IO_OFFSET(map)		(0x36+((map)<<1))
+
+#endif /* _LINUX_TI113X_H */
+
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/topic.h linux/drivers/pcmcia/topic.h
--- v2.3.16/linux/drivers/pcmcia/topic.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/topic.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,96 @@
+/*
+ * topic.h 1.8 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * topic.h $Release$ 1999/08/28 04:01:47
+ */
+
+#ifndef _LINUX_TOPIC_H
+#define _LINUX_TOPIC_H
+
+#ifndef PCI_VENDOR_ID_TOSHIBA
+#define PCI_VENDOR_ID_TOSHIBA		0x1179
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_A
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_A	0x0603
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC95_B
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC95_B	0x060a
+#endif
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC97
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC97	0x060f
+#endif
+
+/* Register definitions for Toshiba ToPIC95 controllers */
+
+#define TOPIC_SOCKET_CONTROL		0x0090	/* 32 bit */
+#define  TOPIC_SCR_IRQSEL		0x00000001
+
+#define TOPIC_SLOT_CONTROL		0x00a0	/* 8 bit */
+#define  TOPIC_SLOT_SLOTON		0x80
+#define  TOPIC_SLOT_SLOTEN		0x40
+#define  TOPIC_SLOT_ID_LOCK		0x20
+#define  TOPIC_SLOT_ID_WP		0x10
+#define  TOPIC_SLOT_PORT_MASK		0x0c
+#define  TOPIC_SLOT_PORT_SHIFT		2
+#define  TOPIC_SLOT_OFS_MASK		0x03
+
+#define TOPIC_CARD_CONTROL		0x00a1	/* 8 bit */
+#define  TOPIC_CCR_INTB			0x20
+#define  TOPIC_CCR_INTA			0x10
+#define  TOPIC_CCR_CLOCK		0x0c
+#define  TOPIC_CCR_PCICLK		0x0c
+#define  TOPIC_CCR_PCICLK_2		0x08
+#define  TOPIC_CCR_CCLK			0x04
+
+#define TOPIC97_INT_CONTROL		0x00a1	/* 8 bit */
+#define  TOPIC97_ICR_INTB		0x20
+#define  TOPIC97_ICR_INTA		0x10
+#define  TOPIC97_ICR_STSIRQNP		0x04
+#define  TOPIC97_ICR_IRQNP		0x02
+#define  TOPIC97_ICR_IRQSEL		0x01
+
+#define TOPIC_CARD_DETECT		0x00a3	/* 8 bit */
+#define  TOPIC_CDR_MODE_PC32		0x80
+#define  TOPIC_CDR_VS1			0x04
+#define  TOPIC_CDR_VS2			0x02
+#define  TOPIC_CDR_SW_DETECT		0x01
+
+#define TOPIC_REGISTER_CONTROL		0x00a4	/* 32 bit */
+#define  TOPIC_RCR_RESUME_RESET		0x80000000
+#define  TOPIC_RCR_REMOVE_RESET		0x40000000
+#define  TOPIC97_RCR_CLKRUN_ENA		0x20000000
+#define  TOPIC97_RCR_TESTMODE		0x10000000
+#define  TOPIC97_RCR_IOPLUP		0x08000000
+#define  TOPIC_RCR_BUFOFF_PWROFF	0x02000000
+#define  TOPIC_RCR_BUFOFF_SIGOFF	0x01000000
+#define  TOPIC97_RCR_CB_DEV_MASK	0x0000f800
+#define  TOPIC97_RCR_CB_DEV_SHIFT	11
+#define  TOPIC97_RCR_RI_DISABLE		0x00000004
+#define  TOPIC97_RCR_CAUDIO_OFF		0x00000002
+#define  TOPIC_RCR_CAUDIO_INVERT	0x00000001
+
+#endif /* _LINUX_TOPIC_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/vg468.h linux/drivers/pcmcia/vg468.h
--- v2.3.16/linux/drivers/pcmcia/vg468.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/vg468.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,106 @@
+/*
+ * vg468.h 1.10 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_VG468_H
+#define _LINUX_VG468_H
+
+/* Special bit in I365_IDENT used for Vadem chip detection */
+#define I365_IDENT_VADEM	0x08
+
+/* Special definitions in I365_POWER */
+#define VG468_VPP2_MASK		0x0c
+#define VG468_VPP2_5V		0x04
+#define VG468_VPP2_12V		0x08
+
+/* Unique Vadem registers */
+#define VG469_VSENSE		0x1f	/* Card voltage sense */
+#define VG469_VSELECT		0x2f	/* Card voltage select */
+#define VG468_CTL		0x38	/* Control register */
+#define VG468_TIMER		0x39	/* Timer control */
+#define VG468_MISC		0x3a	/* Miscellaneous */
+#define VG468_GPIO_CFG		0x3b	/* GPIO configuration */
+#define VG469_EXT_MODE		0x3c	/* Extended mode register */
+#define VG468_SELECT		0x3d	/* Programmable chip select */
+#define VG468_SELECT_CFG	0x3e	/* Chip select configuration */
+#define VG468_ATA		0x3f	/* ATA control */
+
+/* Flags for VG469_VSENSE */
+#define VG469_VSENSE_A_VS1	0x01
+#define VG469_VSENSE_A_VS2	0x02
+#define VG469_VSENSE_B_VS1	0x04
+#define VG469_VSENSE_B_VS2	0x08
+
+/* Flags for VG469_VSELECT */
+#define VG469_VSEL_VCC		0x03
+#define VG469_VSEL_5V		0x00
+#define VG469_VSEL_3V		0x03
+#define VG469_VSEL_MAX		0x0c
+#define VG469_VSEL_EXT_STAT	0x10
+#define VG469_VSEL_EXT_BUS	0x20
+#define VG469_VSEL_MIXED	0x40
+#define VG469_VSEL_ISA		0x80
+
+/* Flags for VG468_CTL */
+#define VG468_CTL_SLOW		0x01	/* 600ns memory timing */
+#define VG468_CTL_ASYNC		0x02	/* Asynchronous bus clocking */
+#define VG468_CTL_TSSI		0x08	/* Tri-state some outputs */
+#define VG468_CTL_DELAY		0x10	/* Card detect debounce */
+#define VG468_CTL_INPACK	0x20	/* Obey INPACK signal? */
+#define VG468_CTL_POLARITY	0x40	/* VCCEN polarity */
+#define VG468_CTL_COMPAT	0x80	/* Compatibility stuff */
+
+#define VG469_CTL_WS_COMPAT	0x04	/* Wait state compatibility */
+#define VG469_CTL_STRETCH	0x10	/* LED stretch */
+
+/* Flags for VG468_TIMER */
+#define VG468_TIMER_ZEROPWR	0x10	/* Zero power control */
+#define VG468_TIMER_SIGEN	0x20	/* Power up */
+#define VG468_TIMER_STATUS	0x40	/* Activity timer status */
+#define VG468_TIMER_RES		0x80	/* Timer resolution */
+#define VG468_TIMER_MASK	0x0f	/* Activity timer timeout */
+
+/* Flags for VG468_MISC */
+#define VG468_MISC_GPIO		0x04	/* General-purpose IO */
+#define VG468_MISC_DMAWSB	0x08	/* DMA wait state control */
+#define VG469_MISC_LEDENA	0x10	/* LED enable */
+#define VG468_MISC_VADEMREV	0x40	/* Vadem revision control */
+#define VG468_MISC_UNLOCK	0x80	/* Unique register lock */
+
+/* Flags for VG469_EXT_MODE_A */
+#define VG469_MODE_VPPST	0x03	/* Vpp steering control */
+#define VG469_MODE_INT_SENSE	0x04	/* Internal voltage sense */
+#define VG469_MODE_CABLE	0x08
+#define VG469_MODE_COMPAT	0x10	/* i82365sl B or DF step */
+#define VG469_MODE_TEST		0x20
+#define VG469_MODE_RIO		0x40	/* Steer RIO to INTR? */
+
+/* Flags for VG469_EXT_MODE_B */
+#define VG469_MODE_B_3V		0x01	/* 3.3v for socket B */
+
+#endif /* _LINUX_VG468_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pcmcia/yenta.h linux/drivers/pcmcia/yenta.h
--- v2.3.16/linux/drivers/pcmcia/yenta.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/pcmcia/yenta.h	Fri Sep  3 12:27:58 1999
@@ -0,0 +1,153 @@
+/*
+ * yenta.h 1.15 1999/08/28 04:01:47
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_YENTA_H
+#define _LINUX_YENTA_H
+
+/* PCI Configuration Registers */
+
+#define PCI_STATUS_CAPLIST		0x10
+#define PCI_CB_CAPABILITY_POINTER	0x14	/* 8 bit */
+#define PCI_CAPABILITY_ID		0x00	/* 8 bit */
+#define  PCI_CAPABILITY_PM		0x01
+#define PCI_NEXT_CAPABILITY		0x01	/* 8 bit */
+#define PCI_PM_CAPABILITIES		0x02	/* 16 bit */
+#define  PCI_PMCAP_PME_D3COLD		0x8000
+#define  PCI_PMCAP_PME_D3HOT		0x4000
+#define  PCI_PMCAP_PME_D2		0x2000
+#define  PCI_PMCAP_PME_D1		0x1000
+#define  PCI_PMCAP_PME_D0		0x0800
+#define  PCI_PMCAP_D2_CAP		0x0400
+#define  PCI_PMCAP_D1_CAP		0x0200
+#define  PCI_PMCAP_DYN_DATA		0x0100
+#define  PCI_PMCAP_DSI			0x0020
+#define  PCI_PMCAP_AUX_PWR		0x0010
+#define  PCI_PMCAP_PMECLK		0x0008
+#define  PCI_PMCAP_VERSION_MASK		0x0007
+#define PCI_PM_CONTROL_STATUS		0x04	/* 16 bit */
+#define  PCI_PMCS_PME_STATUS		0x8000
+#define  PCI_PMCS_DATASCALE_MASK	0x6000
+#define  PCI_PMCS_DATASCALE_SHIFT	13
+#define  PCI_PMCS_DATASEL_MASK		0x1e00
+#define  PCI_PMCS_DATASEL_SHIFT		9
+#define  PCI_PMCS_PME_ENABLE		0x0100
+#define  PCI_PMCS_PWR_STATE_MASK	0x0003
+#define  PCI_PMCS_PWR_STATE_D0		0x0000
+#define  PCI_PMCS_PWR_STATE_D1		0x0001
+#define  PCI_PMCS_PWR_STATE_D2		0x0002
+#define  PCI_PMCS_PWR_STATE_D3		0x0003
+#define PCI_PM_BRIDGE_EXT		0x06	/* 8 bit */
+#define PCI_PM_DATA			0x07	/* 8 bit */
+
+#define CB_PRIMARY_BUS			0x18	/* 8 bit */
+#define CB_CARDBUS_BUS			0x19	/* 8 bit */
+#define CB_SUBORD_BUS			0x1a	/* 8 bit */
+#define CB_LATENCY_TIMER		0x1b	/* 8 bit */
+
+#define CB_MEM_BASE(m)			(0x1c + 8*(m))
+#define CB_MEM_LIMIT(m)			(0x20 + 8*(m))
+#define CB_IO_BASE(m)			(0x2c + 8*(m))
+#define CB_IO_LIMIT(m)			(0x30 + 8*(m))
+
+#define CB_BRIDGE_CONTROL		0x3e	/* 16 bit */
+#define  CB_BCR_PARITY_ENA		0x0001
+#define  CB_BCR_SERR_ENA		0x0002
+#define  CB_BCR_ISA_ENA			0x0004
+#define  CB_BCR_VGA_ENA			0x0008
+#define  CB_BCR_MABORT			0x0020
+#define  CB_BCR_CB_RESET		0x0040
+#define  CB_BCR_ISA_IRQ			0x0080
+#define  CB_BCR_PREFETCH(m)		(0x0100 << (m))
+#define  CB_BCR_WRITE_POST		0x0400
+
+#define CB_LEGACY_MODE_BASE		0x44
+
+/* Memory mapped registers */
+
+#define CB_SOCKET_EVENT			0x0000
+#define  CB_SE_CSTSCHG			0x00000001
+#define  CB_SE_CCD1			0x00000002
+#define  CB_SE_CCD2			0x00000004
+#define  CB_SE_PWRCYCLE			0x00000008
+
+#define CB_SOCKET_MASK			0x0004
+#define  CB_SM_CSTSCHG			0x00000001
+#define  CB_SM_CCD			0x00000006
+#define  CB_SM_PWRCYCLE			0x00000008
+
+#define CB_SOCKET_STATE			0x0008
+#define  CB_SS_CSTSCHG			0x00000001
+#define  CB_SS_CCD1			0x00000002
+#define  CB_SS_CCD2			0x00000004
+#define  CB_SS_PWRCYCLE			0x00000008
+#define  CB_SS_16BIT			0x00000010
+#define  CB_SS_32BIT			0x00000020
+#define  CB_SS_CINT			0x00000040
+#define  CB_SS_BADCARD			0x00000080
+#define  CB_SS_DATALOST			0x00000100
+#define  CB_SS_BADVCC			0x00000200
+#define  CB_SS_5VCARD			0x00000400
+#define  CB_SS_3VCARD			0x00000800
+#define  CB_SS_XVCARD			0x00001000
+#define  CB_SS_YVCARD			0x00002000
+#define  CB_SS_5VSOCKET			0x10000000
+#define  CB_SS_3VSOCKET			0x20000000
+#define  CB_SS_XVSOCKET			0x40000000
+#define  CB_SS_YVSOCKET			0x80000000
+
+#define CB_SOCKET_FORCE			0x000c
+#define  CB_SF_CVSTEST			0x00004000
+
+#define CB_SOCKET_CONTROL		0x0010
+#define  CB_SC_VPP_MASK			0x00000007
+#define   CB_SC_VPP_OFF			0x00000000
+#define   CB_SC_VPP_12V			0x00000001
+#define   CB_SC_VPP_5V			0x00000002
+#define   CB_SC_VPP_3V			0x00000003
+#define   CB_SC_VPP_XV			0x00000004
+#define   CB_SC_VPP_YV			0x00000005
+#define  CB_SC_VCC_MASK			0x00000070
+#define   CB_SC_VCC_OFF			0x00000000
+#define   CB_SC_VCC_5V			0x00000020
+#define   CB_SC_VCC_3V			0x00000030
+#define   CB_SC_VCC_XV			0x00000040
+#define   CB_SC_VCC_YV			0x00000050
+#define  CB_SC_CCLK_STOP		0x00000080
+
+#define CB_SOCKET_POWER			0x0020
+#define  CB_SP_CLK_CTRL			0x00000001
+#define  CB_SP_CLK_CTRL_ENA		0x00010000
+#define  CB_SP_CLK_MODE			0x01000000
+#define  CB_SP_ACCESS			0x02000000
+
+/* Address bits 31..24 for memory windows for 16-bit cards,
+   accessable only by memory mapping the 16-bit register set */
+#define CB_MEM_PAGE(map)		(0x40 + (map))
+
+#endif /* _LINUX_YENTA_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/pnp/isapnp.c linux/drivers/pnp/isapnp.c
--- v2.3.16/linux/drivers/pnp/isapnp.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/pnp/isapnp.c	Tue Sep  7 10:14:37 1999
@@ -287,6 +287,14 @@
 	udelay(100);
 }
 
+/*
+ *	This code is badly broken. We cannot simply pick ports as the 
+ *	ISAPnP specification implies. We should try 4 or 5 safe ports
+ *	then bale by default.
+ *
+ *	This code touches NE2K cards or other devices and your box is
+ *	history.
+ */
 
 static int __init isapnp_isolate_rdp_select(void)
 {
@@ -2102,6 +2110,13 @@
 		printk("isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
 		return -EBUSY;
 	}
+	
+	/*
+	 *	Print a message. The existing ISAPnP code is hanging machines
+	 *	so let the user know where.
+	 */
+	 
+	printk("isapnp: Scanning for Pnp cards...\n");
 	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
 		isapnp_rdp |= 3;
 		isapnp_rdp_res=request_region(isapnp_rdp, 1, "isapnp read");
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.3.16/linux/drivers/scsi/advansys.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/advansys.c	Fri Sep  3 16:35:47 1999
@@ -1,10 +1,10 @@
-/* $Id: advansys.c,v 1.50 1998/05/08 23:39:15 bobf Exp bobf $ */
-#define ASC_VERSION "3.1E"    /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.58 1999/09/03 23:02:16 bobf Exp bobf $ */
+#define ASC_VERSION "3.2F"    /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
  * 
- * Copyright (c) 1995-1998 Advanced System Products, Inc.
+ * Copyright (c) 1995-1999 Advanced System Products, Inc.
  * All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,19 +35,20 @@
   G. Driver Compile Time Options and Debugging
   H. Driver LILO Option
   I. Release History
-  J. Known Problems or Issues
+  J. Known Problems/Fix List
   K. Credits
   L. AdvanSys Contact Information
 
   A. Linux Kernel Testing
 
      This driver has been tested in the following Linux kernels: v1.2.13,
-     v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases
-     of Linux or the latest Linux kernel versions available when this version
-     of the driver was released. The driver should also work in earlier
-     versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver
-     is included with all Linux kernels. Please refer to sections C, D, and
-     E for instructions on adding or upgrading the AdvanSys driver.
+     v1.3.57, v2.0.38, v2.2.12, and v2.3.16. These kernel versions are major
+     releases of Linux or the latest Linux kernel versions available when
+     this version of the driver was released. The driver should also work
+     in earlier versions of the Linux kernel. Beginning with v1.3.58 the
+     AdvanSys driver is included with all Linux kernels. Please refer to
+     sections C, D, and E for instructions on adding or upgrading the
+     AdvanSys driver.
 
   B. Adapters Supported by this Driver
  
@@ -65,15 +66,20 @@
      lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
 
      Connectivity Products:
-        ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1)
-        ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1, 3)
-        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) (Footnote 4)
+        ABP510/5150 - Bus-Master ISA (240 CDB)
+        ABP5140 - Bus-Master ISA PnP (16 CDB)
+        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+        ABP902/3902 - Bus-Master PCI (16 CDB)
+        ABP3905 - Bus-Master PCI (16 CDB)
+        ABP915 - Bus-Master PCI (16 CDB)
         ABP920 - Bus-Master PCI (16 CDB)
-        ABP930 - Bus-Master PCI (16 CDB) (Footnote 5)
+        ABP3922 - Bus-Master PCI (16 CDB)
+        ABP3925 - Bus-Master PCI (16 CDB)
+        ABP930 - Bus-Master PCI (16 CDB)
         ABP930U - Bus-Master PCI Ultra (16 CDB)
         ABP930UA - Bus-Master PCI Ultra (16 CDB)
-        ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
-        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2)
+        ABP960 - Bus-Master PCI MAC/PC (16 CDB)
+        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
      
      Single Channel Products:
         ABP542 - Bus-Master ISA with floppy (240 CDB)
@@ -81,26 +87,23 @@
         ABP842 - Bus-Master VL (240 CDB)
         ABP940 - Bus-Master PCI (240 CDB)
         ABP940U - Bus-Master PCI Ultra (240 CDB)
+        ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
         ABP970 - Bus-Master PCI MAC/PC (240 CDB)
         ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
-        ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB)
+        ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
+        ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+        ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
+        ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
      
-     Multi Channel Products:
+     Multi-Channel Products:
         ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
         ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
         ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+        ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
         ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
         ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+        ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
      
-     Footnotes:
-       1. This board has been shipped by HP with the 4020i CD-R drive.
-          The board has no BIOS so it cannot control a boot device, but
-          it can control any secondary SCSI device.
-       2. This board has been sold by Iomega as a Jaz Jet PCI adapter.
-       3. This board has been sold by SIIG as the i540 SpeedMaster.
-       4. This board has been sold by SIIG as the i542 SpeedMaster.
-       5. This board has been sold by SIIG as the Fast SCSI Pro PCI.
-
   C. Linux v1.2.X - Directions for Adding the AdvanSys Driver
 
      These directions apply to v1.2.13. For versions that follow v1.2.13.
@@ -590,13 +593,63 @@
             flag set to allow IRQ sharing with drivers that do not set
             the SA_INTERRUPT flag. Also display a more descriptive error
             message if request_irq() fails.
-         5. Update to latest Asc and Adv Libraries.
-
-  J. Known Problems or Issues
+         6. Update to latest Asc and Adv Libraries.
 
-         1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
-            the queue depth flow control code when mid-level SCSI changes
-            are included in Linux.
+     3.2A (7/22/99):
+         1. Update Adv Library to 4.16 which includes support for
+            the ASC38C0800 (Ultra2/LVD) IC.
+
+     3.2B (8/23/99):
+         1. Correct PCI compile time option for v2.1.93 and greater
+            kernels, advansys_info() string, and debug compile time
+            option.
+         2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
+            kernels. This caused an LVD detection/BIST problem problem
+            among other things.
+         3. Sort PCI cards by PCI Bus, Slot, Function ascending order
+            to be consistent with the BIOS.
+         4. Update to Asc Library S121 and Adv Library 5.2.
+
+     3.2C (8/24/99):
+         1. Correct PCI card detection bug introduced in 3.2B that
+            prevented PCI cards from being detected in kernels older
+            than v2.1.93.
+
+     3.2D (8/26/99):
+         1. Correct /proc device synchronous speed information display.
+            Also when re-negotiation is pending for a target device
+            note this condition with an * and footnote.
+         2. Correct initialization problem with Ultra-Wide cards that
+            have a pre-3.2 BIOS. A microcode variable changed locations
+            in 3.2 and greater BIOSes which caused WDTR to be attempted
+            erroneously with drives that don't support WDTR.
+
+     3.2E (8/30/99):
+         1. Fix compile error caused by v2.3.13 PCI structure change.
+         2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
+            checksum error for ISA cards.
+         3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
+            SCSI changes that it depended on were never included in Linux.
+
+     3.2F (9/3/99):
+         1. Handle new initial function code added in v2.3.16 for all
+            driver versions.
+            
+  J. Known Problems/Fix List (XXX)
+
+     1. Need to add memory mapping workaround. Test the memory mapping.
+        If it doesn't work revert to I/O port access. Can a test be done
+        safely?
+     2. Handle an interrupt not working. Keep an interrupt counter in
+        the interrupt handler. In the timeout function if the interrupt
+        has not occurred then print a message and run in polled mode.
+     3. Allow bus type scanning order to be changed.
+     4. Need to add support for target mode commands, cf. CAM XPT.
+     5  Need to add support for new Linux SCSI error handling method.
+     6. Need to fix sti/cli code in Asc Library.
+     7. Need to fix abort code in Adv Library.
+     8. Reduce io_request_lock hold time.
+     9. Add big-endian support for Alpha.
 
   K. Credits
 
@@ -617,17 +670,17 @@
      Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
      support in the 3.1A driver.
 
+     Doug Gilbert <dgilbert@interlog.com> has made changes and
+     suggestions to improve the driver and done testing.
+
   L. AdvanSys Contact Information
  
      Mail:                   Advanced System Products, Inc.
                              1150 Ringwood Court
                              San Jose, CA 95131
-     Operator:               1-408-383-9400
+     Operator/Sales:         1-408-383-9400
      FAX:                    1-408-383-9612
-     Tech Support:           1-800-525-7440/1-408-467-2930
-     BBS:                    1-408-383-9540 (14400,N,8,1)
-     Interactive FAX:        1-408-383-9753
-     Customer Direct Sales:  1-800-525-7443/1-408-383-5777
+     Tech Support:           1-408-467-2930
      Tech Support E-Mail:    support@advansys.com
      FTP Site:               ftp.advansys.com (login: anonymous)
      Web Site:               http://www.advansys.com
@@ -660,6 +713,9 @@
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#include <linux/head.h>
+#endif /* verions < v2.1.0 */
 #include <linux/types.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
@@ -745,8 +801,8 @@
  */
 
 #define ASC_LIB_VERSION_MAJOR  1
-#define ASC_LIB_VERSION_MINOR  22
-#define ASC_LIB_SERIAL_NUMBER  113
+#define ASC_LIB_VERSION_MINOR  24
+#define ASC_LIB_SERIAL_NUMBER  121
 
 typedef unsigned char uchar;
 
@@ -832,6 +888,15 @@
 #define  ASC_DVCLIB_CALL_FAILED   (0)
 #define  ASC_DVCLIB_CALL_ERROR    (-1)
 
+/*
+ * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
+ * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
+ * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
+ * SRB structure.
+ */
+#define CC_VERY_LONG_SG_LIST 0
+#define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
+
 #define PortAddr            unsigned short    /* port address size  */
 #define Ptr2Func            ulong
 #define inp(port)           inb(port)
@@ -976,6 +1041,9 @@
 #define SCSI_TYPE_COMM     0x09
 #define SCSI_TYPE_UNKNOWN  0x1F
 #define SCSI_TYPE_NO_DVC   0xFF
+#define INQ_CLOCKING_ST_ONLY    0x0
+#define INQ_CLOCKING_DT_ONLY    0x1
+#define INQ_CLOCKING_ST_AND_DT  0x3
 #define ASC_SCSIDIR_NOCHK    0x00
 #define ASC_SCSIDIR_T2H      0x08
 #define ASC_SCSIDIR_H2T      0x10
@@ -1194,9 +1262,10 @@
 #define ASC_SCSIQ_CDB_BEG             36
 #define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
 #define ASC_SCSIQ_DW_REMAIN_XFER_CNT  60
+#define ASC_SCSIQ_B_FIRST_SG_WK_QP    48
 #define ASC_SCSIQ_B_SG_WK_QP          49
 #define ASC_SCSIQ_B_SG_WK_IX          50
-#define ASC_SCSIQ_W_REQ_COUNT         52
+#define ASC_SCSIQ_W_ALT_DC1           52
 #define ASC_SCSIQ_B_LIST_CNT          6
 #define ASC_SCSIQ_B_CUR_LIST_CNT      7
 #define ASC_SGQ_B_SG_CNTL             4
@@ -1307,6 +1376,8 @@
     ASC_SCSIQ_2         q2;
     uchar               *cdbptr;
     ASC_SG_HEAD         *sg_head;
+    ushort              remain_sg_entry_cnt;
+    ushort              next_sg_index;
 } ASC_SCSI_Q;
 
 typedef struct asc_scsi_req_q {
@@ -1781,6 +1852,7 @@
 #define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX  (ushort)0x8300
 #define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX   (ushort)0x8400
 #define ASC_HALT_SDTR_REJECTED (ushort)0x4000
+#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
 #define ASC_MAX_QNO        0xF8
 #define ASC_DATA_SEC_BEG   (ushort)0x0080
 #define ASC_DATA_SEC_END   (ushort)0x0080
@@ -1876,10 +1948,10 @@
 #define AscGetRiscVarDoneQTail(port)        AscReadLramByte((port), ASCV_DONENEXT_B)
 #define AscPutRiscVarFreeQHead(port, val)   AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
 #define AscPutRiscVarDoneQTail(port, val)   AscWriteLramByte((port), ASCV_DONENEXT_B, val)
-#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) ;
-#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) ;
-#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) ;
-#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) ;
+#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
+#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
+#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
+#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
 #define AscSynIndexToPeriod(index)        (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
 #define AscGetChipSignatureByte(port)     (uchar)inp((port)+IOP_SIG_BYTE)
 #define AscGetChipSignatureWord(port)     (ushort)inpw((port)+IOP_SIG_WORD)
@@ -2074,8 +2146,8 @@
  * --- Adv Library Constants and Macros
  */
 
-#define ADV_LIB_VERSION_MAJOR  3
-#define ADV_LIB_VERSION_MINOR  45
+#define ADV_LIB_VERSION_MAJOR  5
+#define ADV_LIB_VERSION_MINOR  2
 
 /* d_os_dep.h */
 #define ADV_OS_LINUX
@@ -2105,6 +2177,8 @@
 #define iounmap vfree
 #endif /* version < v2.1.0 */
 
+#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
+
 /*
  * Define total number of simultaneous maximum element scatter-gather
  * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number
@@ -2117,18 +2191,9 @@
  */
 #define ADV_MAX_SG_LIST         64
 
-/*
- * Scatter-Gather Definitions per request.
- *
- * Because SG block memory is allocated in virtual memory but is
- * referenced by the microcode as physical memory, we need to do
- * calculations to insure there will be enough physically contiguous
- * memory to support ADV_MAX_SG_LIST SG entries.
- */
-
 /* Number of SG blocks needed. */
 #define ADV_NUM_SG_BLOCK \
-     ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+    ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
 
 /* Total contiguous memory needed for SG blocks. */
 #define ADV_SG_TOTAL_MEM_SIZE \
@@ -2136,26 +2201,16 @@
 
 #define ASC_PAGE_SIZE PAGE_SIZE
 
-/*
- * Number of page crossings possible for the total contiguous virtual memory
- * needed for SG blocks.
- *
- * We need to allocate this many additional SG blocks in virtual memory to
- * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous
- * scatter-gather blocks.
- */
 #define ADV_NUM_PAGE_CROSSING \
     ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
 
-/*
- * Define Adv Library Assertion Macro.
- */
-
 #define ADV_ASSERT(a) ASC_ASSERT(a)
 
 /* a_condor.h */
 #define ADV_PCI_VENDOR_ID               0x10CD
 #define ADV_PCI_DEVICE_ID_REV_A         0x2300
+#define ADV_PCI_DEVID_38C0800_REV1      0x2500
+#define ADV_PCI_DEVID_38C1600_REV1      0x2700
 
 #define ASC_EEP_DVC_CFG_BEGIN           (0x00)
 #define ASC_EEP_DVC_CFG_END             (0x15)
@@ -2164,31 +2219,13 @@
 
 #define ASC_EEP_DELAY_MS                100
 
-/*
- * EEPROM bits reference by the RISC after initialization.
- */
 #define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
 #define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
 #define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
+#define ADV_EEPROM_CIS_LD              0x1000   /* EEPROM Bit 12 */
 
-/*
- * EEPROM configuration format
- *
- * Field naming convention: 
- *
- *  *_enable indicates the field enables or disables the feature. The
- *  value is never reset.
- *
- *  *_able indicates both whether a feature should be enabled or disabled
- *  and whether a device isi capable of the feature. At initialization
- *  this field may be set, but later if a device is found to be incapable
- *  of the feature, the field is cleared.
- *
- * Default values are maintained in a_init.c in the structure
- * Default_EEPROM_Config.
- */
-typedef struct adveep_config
-{                              
+typedef struct adveep_3550_config
+{
                                 /* Word Offset, Description */
 
   ushort cfg_lsw;               /* 00 power up initialization */
@@ -2255,7 +2292,109 @@
   ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
   ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */  
   ushort  num_of_err;           /* 36 number of error */
-} ADVEEP_CONFIG; 
+} ADVEEP_3550_CONFIG; 
+
+typedef struct adveep_38C0800_config
+{
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 12 set - CIS Load */
+                                /*  bit 13 set - Term Polarity Control */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused      */
+  ushort disc_enable;           /* 02 disconnect enable */
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
+  ushort start_motor;           /* 05 send start up motor */
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */
+                                /*    low nibble is scsi id */
+
+  uchar  termination_se;        /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  termination_lvd;       /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  set: BIOS don't act as initiator. */
+                                /*  bit 1  set: BIOS > 1 GB support */
+                                /*  bit 2  set: BIOS > 2 Disk Support */
+                                /*  bit 3  set: BIOS don't support removables */
+                                /*  bit 4  set: BIOS support bootable CD */
+                                /*  bit 5  set: BIOS scan enabled */
+                                /*  bit 6  set: BIOS support multiple LUNs */
+                                /*  bit 7  set: BIOS display of message */
+                                /*  bit 8  set: */
+                                /*  bit 9  set: Reset SCSI bus during init. */
+                                /*  bit 10 set: */
+                                /*  bit 11 set: No verbose initialization. */
+                                /*  bit 12 set: SCSI parity enabled */
+                                /*  bit 13 set: */
+                                /*  bit 14 set: */
+                                /*  bit 15 set: */
+  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
+  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
+  uchar   max_host_qng;         /* 15 maximum host queueing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
+  ushort  reserved36;           /* 36 reserved */
+  ushort  reserved37;           /* 37 reserved */
+  ushort  reserved38;           /* 38 reserved */
+  ushort  reserved39;           /* 39 reserved */
+  ushort  reserved40;           /* 40 reserved */
+  ushort  reserved41;           /* 41 reserved */
+  ushort  reserved42;           /* 42 reserved */
+  ushort  reserved43;           /* 43 reserved */
+  ushort  reserved44;           /* 44 reserved */
+  ushort  reserved45;           /* 45 reserved */
+  ushort  reserved46;           /* 46 reserved */
+  ushort  reserved47;           /* 47 reserved */
+  ushort  reserved48;           /* 48 reserved */
+  ushort  reserved49;           /* 49 reserved */
+  ushort  reserved50;           /* 50 reserved */
+  ushort  reserved51;           /* 51 reserved */
+  ushort  reserved52;           /* 52 reserved */
+  ushort  reserved53;           /* 53 reserved */
+  ushort  reserved54;           /* 54 reserved */
+  ushort  reserved55;           /* 55 reserved */
+  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
+  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
+  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
+  ushort  subsysid;             /* 59 SubSystem ID */
+  ushort  reserved60;           /* 60 reserved */
+  ushort  reserved61;           /* 61 reserved */
+  ushort  reserved62;           /* 62 reserved */
+  ushort  reserved63;           /* 63 reserved */
+} ADVEEP_38C0800_CONFIG;
 
 /*
  * EEPROM Commands
@@ -2279,15 +2418,15 @@
 #define BIOS_CTRL_INIT_VERBOSE       0x0800
 #define BIOS_CTRL_SCSI_PARITY        0x1000
 
-/*
- * ASC 3550 Internal Memory Size - 8KB
- */
-#define ADV_CONDOR_MEMSIZE   0x2000     /* 8 KB Internal Memory */
+#define ADV_3550_MEMSIZE   0x2000       /* 8 KB Internal Memory */
+#define ADV_3550_IOLEN     0x40         /* I/O Port Range in bytes */
 
-/*
- * ASC 3550 I/O Length - 64 bytes
- */
-#define ADV_CONDOR_IOLEN     0x40       /* I/O Port Range in bytes */
+#define ADV_38C0800_MEMSIZE  0x4000     /* 16 KB Internal Memory */
+#define ADV_38C0800_IOLEN    0x100      /* I/O Port Range in bytes */
+
+#define ADV_38C1600_MEMSIZE  0x4000    /* 16 KB Internal Memory */
+#define ADV_38C1600_IOLEN    0x100     /* I/O Port Range 256 bytes */
+#define ADV_38C1600_MEMLEN   0x1000    /* Memory Range 4KB bytes */
 
 /*
  * Byte I/O register address from base of 'iop_base'.
@@ -2306,11 +2445,11 @@
 #define IOPB_RES_ADDR_B         0x0B
 #define IOPB_RES_ADDR_C         0x0C
 #define IOPB_RES_ADDR_D         0x0D
-#define IOPB_RES_ADDR_E         0x0E
+#define IOPB_SOFT_OVER_WR       0x0E
 #define IOPB_RES_ADDR_F         0x0F
 #define IOPB_MEM_CFG            0x10
-#define IOPB_RES_ADDR_11        0x11
-#define IOPB_RES_ADDR_12        0x12
+#define IOPB_GPIO_CNTL          0x11
+#define IOPB_GPIO_DATA          0x12
 #define IOPB_RES_ADDR_13        0x13
 #define IOPB_FLASH_PAGE         0x14
 #define IOPB_RES_ADDR_15        0x15
@@ -2348,8 +2487,8 @@
 #define IOPB_RES_ADDR_35        0x35
 #define IOPB_RES_ADDR_36        0x36
 #define IOPB_RES_ADDR_37        0x37
-#define IOPB_RES_ADDR_38        0x38
-#define IOPB_RES_ADDR_39        0x39
+#define IOPB_RAM_BIST           0x38
+#define IOPB_PLL_TEST           0x39
 #define IOPB_RES_ADDR_3A        0x3A
 #define IOPB_RES_ADDR_3B        0x3B
 #define IOPB_RFIFO_CNT          0x3C
@@ -2402,8 +2541,8 @@
 #define IOPDW_RES_ADDR_8         0x08
 #define IOPDW_RES_ADDR_C         0x0C
 #define IOPDW_RES_ADDR_10        0x10
-#define IOPDW_RES_ADDR_14        0x14
-#define IOPDW_RES_ADDR_18        0x18
+#define IOPDW_COMMA              0x14
+#define IOPDW_COMMB              0x18
 #define IOPDW_RES_ADDR_1C        0x1C
 #define IOPDW_SDMA_ADDR0         0x20
 #define IOPDW_SDMA_ADDR1         0x24
@@ -2453,9 +2592,14 @@
 #define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE  0x00C3
 #define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE  0x00C2
 
+#define ADV_TICKLE_NOP                      0x00
+#define ADV_TICKLE_A                        0x01
+#define ADV_TICKLE_B                        0x02
+#define ADV_TICKLE_C                        0x03
+
 #define ADV_SCSI_CTRL_RSTOUT        0x2000
 
-#define AdvIsIntPending(port)  \
+#define AdvIsIntPending(port) \
     (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
 
 /*
@@ -2492,6 +2636,28 @@
 #define  TERM_CTL_L      0x0010  /* Enable External SCSI Lower Termination */
 #define CABLE_DETECT    0x000F  /* External SCSI Cable Connection Status */
 
+/*
+ * Addendum for ASC-38C0800 Chip
+ */
+#define DIS_TERM_DRV    0x4000  /* 1: Read c_det[3:0], 0: cannot read */
+#define HVD_LVD_SE      0x1C00  /* Device Detect Bits */
+#define  HVD             0x1000  /* HVD Device Detect */
+#define  LVD             0x0800  /* LVD Device Detect */
+#define  SE              0x0400  /* SE Device Detect */
+#define TERM_LVD        0x00C0  /* LVD Termination Bits */
+#define  TERM_LVD_HI     0x0080  /* Enable LVD Upper Termination */
+#define  TERM_LVD_LO     0x0040  /* Enable LVD Lower Termination */
+#define TERM_SE         0x0030  /* SE Termination Bits */
+#define  TERM_SE_HI      0x0020  /* Enable SE Upper Termination */
+#define  TERM_SE_LO      0x0010  /* Enable SE Lower Termination */
+#define C_DET_LVD       0x000C  /* LVD Cable Detect Bits */
+#define  C_DET3          0x0008  /* Cable Detect for LVD External Wide */
+#define  C_DET2          0x0004  /* Cable Detect for LVD Internal Wide */
+#define C_DET_SE        0x0003  /* SE Cable Detect Bits */
+#define  C_DET1          0x0002  /* Cable Detect for SE Internal Wide */
+#define  C_DET0          0x0001  /* Cable Detect for SE Internal Narrow */
+
+
 #define CABLE_ILLEGAL_A 0x7
     /* x 0 0 0  | on  on | Illegal (all 3 connectors are used) */
 
@@ -2499,35 +2665,6 @@
     /* 0 x 0 0  | on  on | Illegal (all 3 connectors are used) */
 
 /*
-   The following table details the SCSI_CFG1 Termination Polarity,
-   Termination Control and Cable Detect bits.
-
-   Cable Detect | Termination
-   Bit 3 2 1 0  | 5   4  | Notes
-   _____________|________|____________________
-       1 1 1 0  | on  on | Internal wide only
-       1 1 0 1  | on  on | Internal narrow only
-       1 0 1 1  | on  on | External narrow only
-       0 x 1 1  | on  on | External wide only
-       1 1 0 0  | on  off| Internal wide and internal narrow
-       1 0 1 0  | on  off| Internal wide and external narrow
-       0 x 1 0  | off off| Internal wide and external wide
-       1 0 0 1  | on  off| Internal narrow and external narrow
-       0 x 0 1  | on  off| Internal narrow and external wide
-       1 1 1 1  | on  on | No devices are attached
-       x 0 0 0  | on  on | Illegal (all 3 connectors are used)
-       0 x 0 0  | on  on | Illegal (all 3 connectors are used)
-  
-       x means don't-care (either '0' or '1')
-  
-       If term_pol (bit 13) is '0' (active-low terminator enable), then:
-           'on' is '0' and 'off' is '1'.
-  
-       If term_pol bit is '1' (meaning active-hi terminator enable), then:
-           'on' is '1' and 'off' is '0'.
- */
-
-/*
  * MEM_CFG Register bit definitions
  */
 #define BIOS_EN         0x40    /* BIOS Enable MIO:14,EEP:14 */
@@ -2564,6 +2701,22 @@
 #define  READ_CMD_MRL    0x02    /* Memory Read Long */
 #define  READ_CMD_MRM    0x03    /* Memory Read Multiple (default) */
 
+/*
+ * ASC-38C0800 RAM BIST Register bit definitions
+ */
+#define RAM_TEST_MODE         0x80
+#define PRE_TEST_MODE         0x40
+#define NORMAL_MODE           0x00
+#define RAM_TEST_DONE         0x10
+#define RAM_TEST_STATUS       0x0F
+#define  RAM_TEST_HOST_ERROR   0x08
+#define  RAM_TEST_INTRAM_ERROR 0x04
+#define  RAM_TEST_RISC_ERROR   0x02
+#define  RAM_TEST_SCSI_ERROR   0x01
+#define  RAM_TEST_SUCCESS      0x00
+#define PRE_TEST_VALUE        0x05
+#define NORMAL_VALUE          0x00
+
 /* a_advlib.h */
 
 /*
@@ -2580,6 +2733,7 @@
 /*
  * ASC_DVC_VAR 'warn_code' values
  */
+#define ASC_WARN_BUSRESET_ERROR         0x0001 /* SCSI Bus Reset error */
 #define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
 #define ASC_WARN_EEPROM_TERMINATION     0x0004 /* EEP termination bad field */
 #define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080 /* PCI config space set error */
@@ -2596,14 +2750,18 @@
  */
 #define ASC_IERR_WRITE_EEPROM       0x0001 /* write EEPROM error */
 #define ASC_IERR_MCODE_CHKSUM       0x0002 /* micro code check sum error */
+#define ASC_IERR_NO_CARRIER         0x0004 /* No more carrier memory. */
 #define ASC_IERR_START_STOP_CHIP    0x0008 /* start/stop chip failed */
 #define ASC_IERR_CHIP_VERSION       0x0040 /* wrong chip version */
 #define ASC_IERR_SET_SCSI_ID        0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE         0x0100 /* HVD attached to LVD connector. */
 #define ASC_IERR_BAD_SIGNATURE      0x0200 /* signature not found */
 #define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
 #define ASC_IERR_SINGLE_END_DEVICE  0x0800 /* Single-end used w/differential */
 #define ASC_IERR_REVERSED_CABLE     0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_RW_LRAM            0x8000 /* read/write local RAM error */
+#define ASC_IERR_BIST_PRE_TEST      0x2000 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST      0x4000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE       0x8000 /* Invalid 'chip_type' setting. */
 
 /*
  * Fixed locations of microcode operating variables.
@@ -2611,37 +2769,38 @@
 #define ASC_MC_CODE_BEGIN_ADDR          0x0028 /* microcode start address */
 #define ASC_MC_CODE_END_ADDR            0x002A /* microcode end address */
 #define ASC_MC_CODE_CHK_SUM             0x002C /* microcode code checksum */
-#define ASC_MC_STACK_BEGIN              0x002E /* microcode stack begin */
-#define ASC_MC_STACK_END                0x0030 /* microcode stack end */
 #define ASC_MC_VERSION_DATE             0x0038 /* microcode version */
 #define ASC_MC_VERSION_NUM              0x003A /* microcode number */
-#define ASCV_VER_SERIAL_W               0x003C /* used in dos_init */
 #define ASC_MC_BIOSMEM                  0x0040 /* BIOS RISC Memory Start */
 #define ASC_MC_BIOSLEN                  0x0050 /* BIOS RISC Memory Length */
-#define ASC_MC_HALTCODE                 0x0094 /* microcode halt code */
-#define ASC_MC_CALLERPC                 0x0096 /* microcode halt caller PC */
-#define ASC_MC_ADAPTER_SCSI_ID          0x0098 /* one ID byte + reserved */
-#define ASC_MC_ULTRA_ABLE               0x009C
+#define ASC_MC_BIOS_SIGNATURE           0x0058 /* BIOS Signature 0x55AA */
+#define ASC_MC_BIOS_VERSION             0x005A /* BIOS Version (2 bytes) */
+#define ASC_MC_SDTR_SPEED1              0x0090 /* SDTR Speed for TID 0-3 */
+#define ASC_MC_SDTR_SPEED2              0x0092 /* SDTR Speed for TID 4-7 */
+#define ASC_MC_SDTR_SPEED3              0x0094 /* SDTR Speed for TID 8-11 */
+#define ASC_MC_SDTR_SPEED4              0x0096 /* SDTR Speed for TID 12-15 */
+#define ASC_MC_CHIP_TYPE                0x009A
+#define ASC_MC_INTRB_CODE               0x009B
+#define ASC_MC_WDTR_ABLE                0x009C
 #define ASC_MC_SDTR_ABLE                0x009E
 #define ASC_MC_TAGQNG_ABLE              0x00A0
 #define ASC_MC_DISC_ENABLE              0x00A2
+#define ASC_MC_IDLE_CMD_STATUS          0x00A4
 #define ASC_MC_IDLE_CMD                 0x00A6
-#define ASC_MC_IDLE_PARA_STAT           0x00A8
+#define ASC_MC_IDLE_CMD_PARAMETER       0x00A8
 #define ASC_MC_DEFAULT_SCSI_CFG0        0x00AC
 #define ASC_MC_DEFAULT_SCSI_CFG1        0x00AE
 #define ASC_MC_DEFAULT_MEM_CFG          0x00B0
 #define ASC_MC_DEFAULT_SEL_MASK         0x00B2
-#define ASC_MC_RISC_NEXT_READY          0x00B4
-#define ASC_MC_RISC_NEXT_DONE           0x00B5
 #define ASC_MC_SDTR_DONE                0x00B6
 #define ASC_MC_NUMBER_OF_QUEUED_CMD     0x00C0
 #define ASC_MC_NUMBER_OF_MAX_CMD        0x00D0
 #define ASC_MC_DEVICE_HSHK_CFG_TABLE    0x0100
-#define ASC_MC_WDTR_ABLE                0x0120 /* Wide Transfer TID bitmask. */
 #define ASC_MC_CONTROL_FLAG             0x0122 /* Microcode control flag. */
 #define ASC_MC_WDTR_DONE                0x0124
-#define ASC_MC_HOST_NEXT_READY          0x0128 /* Host Next Ready RQL Entry. */
-#define ASC_MC_HOST_NEXT_DONE           0x0129 /* Host Next Done RQL Entry. */
+#define ASC_MC_CAM_MODE_MASK            0x015E /* CAM mode TID bitmask. */
+#define ASC_MC_ICQ                      0x0160
+#define ASC_MC_IRQ                      0x0164
 
 /*
  * BIOS LRAM variable absolute offsets.
@@ -2650,7 +2809,6 @@
 #define BIOS_CODELEN    0x56
 #define BIOS_SIGNATURE  0x58
 #define BIOS_VERSION    0x5A
-#define BIOS_SIGNATURE  0x58
 
 /*
  * Microcode Control Flags
@@ -2667,50 +2825,61 @@
 #define HSHK_CFG_RATE           0x0F00
 #define HSHK_CFG_OFFSET         0x001F
 
-/*
- * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF)
- *
- * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes 
- * starting at LRAM address 0x1200 is 8 bytes and has the following
- * structure. Only 253 of these are actually used for command queues.
- */
-
-#define ASC_MC_RISC_Q_LIST_BASE         0x1200
-#define ASC_MC_RISC_Q_LIST_SIZE         0x0008
-#define ASC_MC_RISC_Q_TOTAL_CNT         0x00FF /* Num. queue slots in LRAM. */
-#define ASC_MC_RISC_Q_FIRST             0x0001
-#define ASC_MC_RISC_Q_LAST              0x00FF
-
 #define ASC_DEF_MAX_HOST_QNG    0xFD /* Max. number of host commands (253) */
 #define ASC_DEF_MIN_HOST_QNG    0x10 /* Min. number of host commands (16) */
 #define ASC_DEF_MAX_DVC_QNG     0x3F /* Max. number commands per device (63) */
 #define ASC_DEF_MIN_DVC_QNG     0x04 /* Min. number commands per device (4) */
 
-/* RISC Queue List structure - 8 bytes */
-#define RQL_FWD     0     /* forward pointer (1 byte) */
-#define RQL_BWD     1     /* backward pointer (1 byte) */
-#define RQL_STATE   2     /* state byte - free, ready, done, aborted (1 byte) */
-#define RQL_TID     3     /* request target id (1 byte) */
-#define RQL_PHYADDR 4     /* request physical pointer (4 bytes) */
-     
-/* RISC Queue List state values */
-#define ASC_MC_QS_FREE                  0x00
-#define ASC_MC_QS_READY                 0x01
-#define ASC_MC_QS_DONE                  0x40
-#define ASC_MC_QS_ABORTED               0x80
-
-/* RISC Queue List pointer values */
-#define ASC_MC_NULL_Q                   0x00            /* NULL_Q == 0   */
-#define ASC_MC_BIOS_Q                   0xFF            /* BIOS_Q = 255  */
-
-/* ASC_SCSI_REQ_Q 'cntl' field values */
-#define ASC_MC_QC_START_MOTOR           0x02     /* Issue start motor. */
-#define ASC_MC_QC_NO_OVERRUN            0x04     /* Don't report overrun. */
-#define ASC_MC_QC_FIRST_DMA             0x08     /* Internal microcode flag. */
-#define ASC_MC_QC_ABORTED               0x10     /* Request aborted by host. */
-#define ASC_MC_QC_REQ_SENSE             0x20     /* Auto-Request Sense. */
-#define ASC_MC_QC_DOS_REQ               0x80     /* Request issued by DOS. */
+#define ASC_QC_DATA_CHECK  0x01 /* Require ASC_QC_DATA_OUT set or clear. */
+#define ASC_QC_DATA_OUT    0x02 /* Data out DMA transfer. */
+#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
+#define ASC_QC_NO_OVERRUN  0x08 /* Don't report overrun. */
+#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
+
+#define ASC_QSC_NO_DISC     0x01 /* Don't allow disconnect for request. */
+#define ASC_QSC_NO_TAGMSG   0x02 /* Don't allow tag queuing for request. */
+#define ASC_QSC_NO_SYNC     0x04 /* Don't use Synch. transfer on request. */
+#define ASC_QSC_NO_WIDE     0x08 /* Don't use Wide transfer on request. */
+#define ASC_QSC_REDO_DTR    0x10 /* Renegotiate WDTR/SDTR before request. */
+/*
+ * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
+ * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
+ */
+#define ASC_QSC_HEAD_TAG    0x40 /* Use Head Tag Message (0x21). */
+#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+
+typedef struct adv_carr_t
+{
+    ulong       carr_va;       /* Carrier Virtual Address */
+    ulong       carr_pa;       /* Carrier Physical Address */
+    ulong       areq_vpa;      /* ASC_SCSI_REQ_Q Virtual or Physical Address */
+    /*
+     * next_vpa [31:4]            Carrier Virtual or Physical Next Pointer
+     *
+     * next_vpa [3:1]             Reserved Bits
+     * next_vpa [0]               Done Flag set in Response Queue.
+     */
+    ulong       next_vpa;
+} ADV_CARR_T;
+
+/*
+ * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
+ */
+#define ASC_NEXT_VPA_MASK       0xFFFFFFF0
 
+#define ASC_RQ_DONE             0x00000001
+#define ASC_CQ_STOPPER          0x00000000
+
+#define ASC_GET_CARRP(carrp) ((ADV_CARR_T *) ((carrp) & ASC_NEXT_VPA_MASK))
+
+#define ADV_PAGE_SIZE   4096    /* Assume 4KB page size. */
+
+#define ADV_CARRIER_NUM_PAGE_CROSSING \
+    (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
+        (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+
+#define ADV_CARRIER_BUFSIZE \
+    ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
 
 /*
  * ASC_SCSI_REQ_Q 'a_flag' definitions
@@ -2720,6 +2889,11 @@
  */
 #define ADV_POLL_REQUEST                0x01   /* poll for request completion */
 #define ADV_SCSIQ_DONE                  0x02   /* request done */
+#define ADV_DONT_RETRY                  0x08   /* don't do retry */
+
+#define ADV_CHIP_ASC3550          0x01   /* Ultra-Wide IC */
+#define ADV_CHIP_ASC38C0800       0x02   /* Ultra2-Wide/LVD IC */
+#define ADV_CHIP_ASC38C1600       0x03   /* Ultra3-Wide/LVD2 IC */
 
 /*
  * Adapter temporary configuration structure
@@ -2744,12 +2918,20 @@
   ushort pci_slot_info;     /* high byte device/function number */
                             /* bits 7-3 device num., bits 2-0 function num. */
                             /* low byte bus num. */
-  ushort bios_boot_wait;    /* BIOS boot time delay */
   ushort serial1;           /* EEPROM serial number word 1 */
   ushort serial2;           /* EEPROM serial number word 2 */
   ushort serial3;           /* EEPROM serial number word 3 */
 } ADV_DVC_CFG; 
 
+struct adv_dvc_var;
+struct adv_scsi_req_q;
+
+typedef void (* ADV_ISR_CALLBACK)
+    (struct adv_dvc_var *, struct adv_scsi_req_q *);
+
+typedef void (* ADV_ASYNC_CALLBACK)
+    (struct adv_dvc_var *, uchar);
+
 /*
  * Adapter operation variable structure.
  *
@@ -2766,23 +2948,32 @@
   AdvPortAddr iop_base;   /* I/O port address */
   ushort err_code;        /* fatal error code */
   ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
-  Ptr2Func isr_callback;  /* pointer to function, called in AdvISR() */
-  Ptr2Func sbreset_callback;  /* pointer to function, called in AdvISR() */
+  ADV_ISR_CALLBACK isr_callback;
+  ADV_ASYNC_CALLBACK async_callback;
   ushort wdtr_able;       /* try WDTR for a device */
   ushort sdtr_able;       /* try SDTR for a device */
   ushort ultra_able;      /* try SDTR Ultra speed for a device */
+  ushort sdtr_speed1;     /* EEPROM SDTR Speed for TID 0-3   */
+  ushort sdtr_speed2;     /* EEPROM SDTR Speed for TID 4-7   */
+  ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
+  ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
   ushort tagqng_able;     /* try tagged queuing with a device */
   uchar  max_dvc_qng;     /* maximum number of tagged commands per device */
   ushort start_motor;     /* start motor command allowed */
   uchar  scsi_reset_wait; /* delay in seconds after scsi bus reset */
   uchar  chip_no;         /* should be assigned by caller */
   uchar  max_host_qng;    /* maximum number of Q'ed command allowed */
-  uchar  cur_host_qng;    /* total number of queue command */
   uchar  irq_no;          /* IRQ number */
   ushort no_scam;         /* scam_tolerant of EEPROM */
-  ushort idle_cmd_done;   /* microcode idle command done set by AdvISR() */
   ulong  drv_ptr;         /* driver pointer to private structure */
   uchar  chip_scsi_id;    /* chip SCSI target ID */
+  uchar  chip_type;
+  uchar  bist_err_code;
+  ADV_CARR_T *carrier_buf;
+  ADV_CARR_T *carr_freelist; /* Carrier free list. */
+  ADV_CARR_T *icq_sp;  /* Initiator command queue stopper pointer. */
+  ADV_CARR_T *irq_sp;  /* Initiator response queue stopper pointer. */
+  ushort carr_pending_cnt;    /* Count of pending carriers. */
  /*
   * Note: The following fields will not be used after initialization. The
   * driver may discard the buffer after initialization is done.
@@ -2795,17 +2986,17 @@
 typedef struct asc_sg_block {
     uchar reserved1; 
     uchar reserved2; 
-    uchar first_entry_no;             /* starting entry number */
-    uchar last_entry_no;              /* last entry number */
+    uchar reserved3;
+    uchar sg_cnt;                     /* Valid entries in block. */
     struct asc_sg_block *sg_ptr; /* links to the next sg block */
     struct  {
-        ulong sg_addr;                /* SG element address */
-        ulong sg_count;               /* SG element count */
+        ulong sg_addr;                /* SG element address. */
+        ulong sg_count;               /* SG element count. */
     } sg_list[NO_OF_SG_PER_BLOCK];
 } ADV_SG_BLOCK;
 
 /*
- * ASC_SCSI_REQ_Q - microcode request structure
+ * ADV_SCSI_REQ_Q - microcode request structure
  *
  * All fields in this structure up to byte 60 are used by the microcode.
  * The microcode makes assumptions about the size and ordering of fields
@@ -2814,35 +3005,36 @@
  */
 typedef struct adv_scsi_req_q {
     uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
-    uchar       sg_entry_cnt;   /* SG element count. Zero for no SG. */
+    uchar       reserved;
     uchar       target_id;      /* Device target identifier. */
     uchar       target_lun;     /* Device target logical unit number. */
     ulong       data_addr;      /* Data buffer physical address. */
     ulong       data_cnt;       /* Data count. Ucode sets to residual. */
-    ulong       sense_addr;     /* Sense buffer physical address. */
-    ulong       srb_ptr;        /* Driver request pointer. */
-    uchar       a_flag;         /* Adv Library flag field. */
-    uchar       sense_len;      /* Auto-sense length. Ucode sets to residual. */
+    ulong       sense_addr;
+    ulong       carr_pa;
+    uchar       mflag;
+    uchar       sense_len;
     uchar       cdb_len;        /* SCSI CDB length. */
-    uchar       tag_code;       /* SCSI-2 Tag Queue Code: 00, 20-22. */
+    uchar       scsi_cntl;
     uchar       done_status;    /* Completion status. */
     uchar       scsi_status;    /* SCSI status byte. */
     uchar       host_status;    /* Ucode host status. */
-    uchar       ux_sg_ix;       /* Ucode working SG variable. */
+    uchar       sg_working_ix;
     uchar       cdb[12];        /* SCSI command block. */
     ulong       sg_real_addr;   /* SG list physical address. */
-    struct adv_scsi_req_q *free_scsiq_link;
-    ulong       ux_wk_data_cnt; /* Saved data count at disconnection. */
+    ulong       scsiq_rptr;
+    ulong       sg_working_data_cnt;
     struct adv_scsi_req_q *scsiq_ptr;
-    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+    ulong       carr_va;
     /*
      * End of microcode structure - 60 bytes. The rest of the structure
      * is used by the Adv Library and ignored by the microcode.
      */
-    ulong       vsense_addr;    /* Sense buffer virtual address. */
+    ulong       srb_ptr;
+    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
     ulong       vdata_addr;     /* Data buffer virtual address. */
-    uchar       orig_sense_len; /* Original length of sense buffer. */
-} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */
+    uchar       a_flag;
+} ADV_SCSI_REQ_Q;
 
 /*
  * Microcode idle loop commands
@@ -2853,7 +3045,12 @@
 #define IDLE_CMD_SEND_INT            0x0004
 #define IDLE_CMD_ABORT               0x0008
 #define IDLE_CMD_DEVICE_RESET        0x0010
-#define IDLE_CMD_SCSI_RESET          0x0020
+#define IDLE_CMD_SCSI_RESET_START    0x0020 /* Assert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_END      0x0040 /* Deassert SCSI Bus Reset */
+#define IDLE_CMD_SCSIREQ             0x0080
+
+#define IDLE_CMD_STATUS_SUCCESS      0x0001
+#define IDLE_CMD_STATUS_FAILURE      0x0002
 
 /*
  * AdvSendIdleCmd() flag definitions.
@@ -2863,8 +3060,17 @@
 /*
  * Wait loop time out values.
  */
-#define SCSI_WAIT_10_SEC             10         /* 10 seconds */
-#define SCSI_MS_PER_SEC              1000       /* milliseconds per second */
+#define SCSI_WAIT_10_SEC             10UL    /* 10 seconds */
+#define SCSI_WAIT_100_MSEC           100UL   /* 100 milliseconds */
+#define SCSI_US_PER_MSEC             1000    /* microseconds per millisecond */
+#define SCSI_MS_PER_SEC              1000UL  /* milliseconds per second */
+#define SCSI_MAX_RETRY               10      /* retry count */
+
+#define ADV_ASYNC_RDMA_FAILURE          0x01 /* Fatal RDMA failure. */
+#define ADV_ASYNC_SCSI_BUS_RESET_DET    0x02 /* Detected SCSI Bus Reset. */
+#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
+
+#define ADV_HOST_SCSI_BUS_RESET      0x80 /* Host Initiated SCSI Bus Reset. */
 
 /*
  * Device drivers must define the following functions.
@@ -2886,21 +3092,23 @@
 STATIC int     AdvISR(ADV_DVC_VAR *);
 STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
 STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
-STATIC int     AdvResetSB(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+STATIC int     AdvResetChipAndSB(ADV_DVC_VAR *);
+STATIC int     AdvResetSB(ADV_DVC_VAR *asc_dvc);
 
 /*
  * Internal Adv Library functions.
  */
-STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int);
-STATIC void   AdvResetChip(ADV_DVC_VAR *);
-STATIC int    AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong);
 STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int    AdvInitFromEEP(ADV_DVC_VAR *);
-STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
-STATIC void   AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC int    AdvInitFrom3550EEP(ADV_DVC_VAR *);
+STATIC int    AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC void   AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+STATIC void   AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
 STATIC void   AdvWaitEEPCmd(AdvPortAddr);
 STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
-STATIC void   AdvResetSCSIBus(ADV_DVC_VAR *);
 
 /*
  * PCI Bus Definitions
@@ -2911,20 +3119,16 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
 
 /* Read byte from a register. */
-#define AdvReadByteRegister(iop_base, reg_off) \
-     (inp((iop_base) + (reg_off)))
+#define AdvReadByteRegister(iop_base, reg_off) (inp((iop_base) + (reg_off)))
 
 /* Write byte to a register. */
-#define AdvWriteByteRegister(iop_base, reg_off, byte) \
-     (outp((iop_base) + (reg_off), (byte)))
+#define AdvWriteByteRegister(iop_base, reg_off, byte) (outp((iop_base) + (reg_off), (byte)))
 
 /* Read word (2 bytes) from a register. */
-#define AdvReadWordRegister(iop_base, reg_off) \
-     (inpw((iop_base) + (reg_off)))
+#define AdvReadWordRegister(iop_base, reg_off) (inpw((iop_base) + (reg_off)))
 
 /* Write word (2 bytes) to a register. */
-#define AdvWriteWordRegister(iop_base, reg_off, word) \
-     (outpw((iop_base) + (reg_off), (word)))
+#define AdvWriteWordRegister(iop_base, reg_off, word) (outpw((iop_base) + (reg_off), (word)))
 
 /* Read byte from LRAM. */
 #define AdvReadByteLram(iop_base, addr, byte) \
@@ -3060,9 +3264,9 @@
  *      ADV_TRUE(1) - Queue was successfully aborted.
  *      ADV_FALSE(0) - Queue was not found on the active queue list.
  */
-#define AdvAbortSRB(asc_dvc, srb_ptr) \
-    AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
-                (ulong) (srb_ptr), 0)
+#define AdvAbortQueue(asc_dvc, scsiq) \
+        AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
+                       (ulong) (scsiq))
 
 /*
  * Send a Bus Device Reset Message to the specified target ID.
@@ -3077,7 +3281,7 @@
  */
 #define AdvResetDevice(asc_dvc, target_id) \
         AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
-                    (ulong) (target_id), 0)
+                    (ulong) (target_id))
 
 /*
  * SCSI Wide Type definition.
@@ -3120,22 +3324,25 @@
 #define QHSTA_M_SXFR_XFR_OFLW       0x12 /* SXFR_STATUS Transfer Overflow */
 #define QHSTA_M_SXFR_XFR_PH_ERR     0x24 /* SXFR_STATUS Transfer Phase Error */
 #define QHSTA_M_SXFR_UNKNOWN_ERROR  0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_SCSI_BUS_RESET      0x30 /* Request aborted from SBR */
+#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
+#define QHSTA_M_BUS_DEVICE_RESET    0x32 /* Request aborted from BDR */
+#define QHSTA_M_DIRECTION_ERR       0x35 /* Data Phase mismatch */
+#define QHSTA_M_DIRECTION_ERR_HUNG  0x36 /* Data Phase mismatch and bus hang */
 #define QHSTA_M_WTM_TIMEOUT         0x41
 #define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
 #define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
 #define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
 #define QHSTA_M_INVALID_DEVICE      0x45 /* Bad target ID */
+#define QHSTA_M_FROZEN_TIDQ         0x46 /* TID Queue frozen. */
+#define QHSTA_M_SGBACKUP_ERROR      0x47 /* Scatter-Gather backup error */
 
-typedef int (* ADV_ISR_CALLBACK)
-    (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-
-typedef int (* ADV_SBRESET_CALLBACK)
-    (ADV_DVC_VAR *);
 
 /*
  * Default EEPROM Configuration structure defined in a_init.c.
  */
-extern ADVEEP_CONFIG Default_EEPROM_Config;
+extern ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
+extern ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
 
 /*
  * DvcGetPhyAddr() flag arguments
@@ -3145,9 +3352,11 @@
 #define ADV_IS_SENSE_FLAG       0x04 /* 'addr' is sense virtual pointer */
 #define ADV_IS_DATA_FLAG        0x08 /* 'addr' is data virtual pointer */
 #define ADV_IS_SGLIST_FLAG      0x10 /* 'addr' is sglist virtual pointer */
+#define ADV_IS_CARRIER_FLAG     0x20 /* 'addr' is ADV_CARR_T pointer */
 
 /* Return the address that is aligned at the next doubleword >= to 'addr'. */
 #define ADV_DWALIGN(addr)       (((ulong) (addr) + 0x3) & ~0x3)
+#define ADV_16BALIGN(addr)     (((ulong) (addr) + 0xF) & ~0xF)
 
 /*
  * Total contiguous memory needed for driver SG blocks.
@@ -3174,6 +3383,44 @@
 #define ADV_ASSERT(a)
 #endif /* ADV_ASSERT */
 
+typedef struct {
+  uchar peri_dvc_type   : 5;    /* peripheral device type */
+  uchar peri_qualifier  : 3;    /* peripheral qualifier */
+  uchar dvc_type_modifier : 7;  /* device type modifier (for SCSI I) */
+  uchar rmb      : 1;           /* RMB - removable medium bit */
+  uchar ansi_apr_ver : 3;       /* ANSI approved version */
+  uchar ecma_ver : 3;           /* ECMA version */
+  uchar iso_ver  : 2;           /* ISO version */
+  uchar rsp_data_fmt : 4;       /* response data format */
+                                /* 0 SCSI 1 */
+                                /* 1 CCS */
+                                /* 2 SCSI-2 */
+                                /* 3-F reserved */
+  uchar res1     : 2;           /* reserved */
+  uchar TemIOP   : 1;           /* terminate I/O process bit (see 5.6.22) */
+  uchar aenc     : 1;           /* asynch. event notification (processor) */
+  uchar add_len;                /* additional length */
+  uchar res2;                   /* reserved */
+  uchar res3;                   /* reserved */
+  uchar StfRe   : 1;            /* soft reset implemented */
+  uchar CmdQue  : 1;            /* command queuing */
+  uchar res4    : 1;            /* reserved */
+  uchar Linked  : 1;            /* linked command for this logical unit */
+  uchar Sync    : 1;            /* synchronous data transfer */
+  uchar WBus16  : 1;            /* wide bus 16 bit data transfer */
+  uchar WBus32  : 1;            /* wide bus 32 bit data transfer */
+  uchar RelAdr  : 1;            /* relative addressing mode */
+  uchar vendor_id[8];           /* vendor identification */
+  uchar product_id[16];         /* product identification */
+  uchar product_rev_level[4];   /* product revision level */
+  uchar vendor_specific[20];    /* vendor specific */
+  uchar IUS      : 1;           /* information unit supported */
+  uchar QAS      : 1;           /* quick arbitrate supported */
+  uchar Clocking : 2;           /* clocking field */
+  uchar res5     : 4;           /* reserved */
+  uchar res6;                   /* reserved */
+} ADV_SCSI_INQUIRY; /* 58 bytes */
+
 
 /*
  * --- Driver Constants and Macros
@@ -3203,11 +3450,17 @@
  * are not used when the driver is built as a module, cf. linux/init.h.
  */
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23)
+#define ASC_INITFUNC(type, func)        type func
 #define ASC_INITDATA
 #define ASC_INIT
 #else /* version >= v2.1.23 */
-#define ASC_INITDATA            __initdata
-#define ASC_INIT                __init
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,16)
+#define ASC_INITFUNC(type, func)        __initfunc(type func)
+#else /* version >= v2.3.16 */
+#define ASC_INITFUNC(type, func)        type __init func
+#endif /* version >= v2.3.16 */
+#define ASC_INITDATA                    __initdata
+#define ASC_INIT                        __init
 #endif /* version >= v2.1.23 */
 
 #define ASC_INFO_SIZE           128            /* advansys_info() line size */
@@ -3350,11 +3603,12 @@
 #define PCI_MAX_BUS             0xFF
 #define PCI_IOADDRESS_MASK      0xFFFE
 #define ASC_PCI_VENDORID        0x10CD
-#define ASC_PCI_DEVICE_ID_CNT   4       /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_CNT   5       /* PCI Device ID count. */
 #define ASC_PCI_DEVICE_ID_1100  0x1100
 #define ASC_PCI_DEVICE_ID_1200  0x1200
 #define ASC_PCI_DEVICE_ID_1300  0x1300
-#define ASC_PCI_DEVICE_ID_2300  0x2300
+#define ASC_PCI_DEVICE_ID_2300  0x2300  /* ASC-3550 */
+#define ASC_PCI_DEVICE_ID_2500  0x2500  /* ASC-38C0800 */
 
 /* PCI IO Port Addresses to generate special cycle */
 
@@ -3660,14 +3914,12 @@
     ADV_SCSI_BIT_ID_TYPE init_tidmask;          /* Target init./valid mask */
     Scsi_Device          *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
     ushort               reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
-#if ASC_QUEUE_FLOW_CONTROL
-    ushort               nerrcnt[ADV_MAX_TID+1]; /* No error request count */
-#endif /* ASC_QUEUE_FLOW_CONTROL */
     ADV_SCSI_BIT_ID_TYPE queue_full;            /* Queue full mask */
     ushort               queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
     union {
-        ASCEEP_CONFIG    asc_eep;               /* Narrow EEPROM config. */
-        ADVEEP_CONFIG    adv_eep;               /* Wide EEPROM config. */
+        ASCEEP_CONFIG         asc_eep;          /* Narrow EEPROM config. */
+        ADVEEP_3550_CONFIG    adv_3550_eep;     /* 3550 EEPROM config. */
+        ADVEEP_38C0800_CONFIG adv_38C0800_eep;  /* 38C0800 EEPROM config. */
     } eep_config;
     ulong                last_reset;            /* Saved last reset time */
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -3690,6 +3942,7 @@
      */
     void                 *ioremap_addr;         /* I/O Memory remap address. */
     ushort               ioport;                /* I/O Port address. */
+    ADV_CARR_T           *orig_carrp;           /* ADV_CARR_T memory block. */
     adv_req_t            *orig_reqp;            /* adv_req_t memory block. */
     adv_req_t            *adv_reqp;             /* Request structures. */
     adv_sgblk_t          *orig_sgblkp;          /* adv_sgblk_t memory block. */
@@ -3808,6 +4061,7 @@
  * 16 elements of each structure. v1.3.0 kernels will probably
  * not need any more than this number.
  */
+uchar adv_carr_buf[20 * sizeof(ADV_CARR_T)] = { 0 };
 uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
 uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 };
 #endif /* version >= v1,3,0 */
@@ -3854,6 +4108,7 @@
 STATIC int        adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *);
 STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
 STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
 STATIC int        asc_srch_pci_dev(PCI_DEVICE *);
@@ -3883,7 +4138,7 @@
 STATIC int        asc_prt_line(char *, int, char *fmt, ...);
 #endif /* version >= v1.3.0 */
 
-/* Declaration for Asc Library internal functions reference by driver. */
+/* Declaration for Asc Library internal functions referenced by driver. */
 STATIC int          AscFindSignature(PortAddr);
 STATIC ushort       AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
 
@@ -3940,7 +4195,6 @@
                    int hostno, int inout)
 {
 #ifdef CONFIG_PROC_FS
-
     struct Scsi_Host    *shp;
     asc_board_t         *boardp;
     int                 i;
@@ -4150,9 +4404,9 @@
 #else /* CONFIG_PROC_FS */
     return 0;
 #endif /* CONFIG_PROC_FS */
-
 }
 #endif /* version >= v1.3.0 */
+
 /*
  * advansys_detect()
  *
@@ -4166,20 +4420,27 @@
  * it must not call SCSI mid-level functions including scsi_malloc()
  * and scsi_free().
  */
-int ASC_INIT
+ASC_INITFUNC(
+int,
 advansys_detect(Scsi_Host_Template *tpnt)
+)
 {
     static int          detect_called = ASC_FALSE;
     int                 iop;
     int                 bus;
-    struct Scsi_Host    *shp;
-    asc_board_t         *boardp;
+    struct Scsi_Host    *shp = NULL;
+    asc_board_t         *boardp = NULL;
     ASC_DVC_VAR         *asc_dvc_varp = NULL;
     ADV_DVC_VAR         *adv_dvc_varp = NULL;
     int                 ioport = 0;
     int                 share_irq = FALSE;
+    int                 iolen = 0;
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
+    int                 pci_init_search = 0;
+    PCI_DEVICE          pci_device[ASC_NUM_BOARD_SUPPORTED];
+    int                 pci_card_cnt_max = 0;
+    int                 pci_card_cnt = 0;
     PCI_DEVICE          pciDevice;
     PCI_CONFIG_SPACE    pciConfig;
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -4188,13 +4449,18 @@
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
+    int                 pci_init_search = 0;
+    struct pci_dev      *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
+    int                 pci_card_cnt_max = 0;
+    int                 pci_card_cnt = 0;
     struct pci_dev      *pci_devp = NULL;
     int                 pci_device_id_cnt = 0;
     unsigned int        pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
                                     ASC_PCI_DEVICE_ID_1100,
                                     ASC_PCI_DEVICE_ID_1200,
                                     ASC_PCI_DEVICE_ID_1300,
-                                    ASC_PCI_DEVICE_ID_2300
+                                    ASC_PCI_DEVICE_ID_2300,
+                                    ASC_PCI_DEVICE_ID_2500
                         };
     unsigned long       pci_memory_address;
 #endif /* CONFIG_PCI */
@@ -4308,10 +4574,10 @@
                                 (AscGetChipVersion(iop, ASC_IS_ISA) &
                                  ASC_CHIP_VER_ISA_BIT) == 0) {
                                  /*
-                                 * Don't clear 'asc_ioport[ioport]'. Try
-                                 * this board again for VL. Increment
-                                 * 'ioport' past this board.
-                                 */
+                                  * Don't clear 'asc_ioport[ioport]'. Try
+                                  * this board again for VL. Increment
+                                  * 'ioport' past this board.
+                                  */
                                  ioport++;
                                  goto ioport_try_again;
                             }
@@ -4330,12 +4596,54 @@
                 iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
                 break;
 
+            case ASC_IS_PCI:
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
-            case ASC_IS_PCI:
-                if (asc_srch_pci_dev(&pciDevice) != PCI_DEVICE_FOUND) {
+                if (pci_init_search == 0) {
+                    int i, j;
+
+                    pci_init_search = 1;
+
+                    /* Find all PCI cards. */
+                    while (asc_srch_pci_dev(&pciDevice) == PCI_DEVICE_FOUND) {
+                        pci_device[pci_card_cnt_max++] = pciDevice;
+                    }
+
+                    /*
+                     * Sort PCI cards in ascending order by PCI Bus, Slot,
+                     * and Device Number.
+                     */
+                    for (i = 0; i < pci_card_cnt_max - 1; i++)
+                    {
+                        for (j = i + 1; j < pci_card_cnt_max; j++) {
+                            if ((pci_device[j].busNumber <
+                                 pci_device[i].busNumber) ||
+                                ((pci_device[j].busNumber ==
+                                  pci_device[i].busNumber) &&
+                                  (pci_device[j].slotNumber <
+                                   pci_device[i].slotNumber)) ||
+                                ((pci_device[j].busNumber ==
+                                  pci_device[i].busNumber) &&
+                                  (pci_device[j].slotNumber ==
+                                   pci_device[i].slotNumber) &&
+                                  (pci_device[j].devFunc <
+                                   pci_device[i].devFunc))) {
+                                pciDevice = pci_device[i];
+                                pci_device[i] = pci_device[j];
+                                pci_device[j] = pciDevice;
+                            }
+                        }
+                    }
+
+                    pci_card_cnt = 0;
+                } else {
+                    pci_card_cnt++;
+                }
+
+                if (pci_card_cnt == pci_card_cnt_max) {
                     iop = 0;
                 } else {
+                    pciDevice = pci_device[pci_card_cnt];
                     ASC_DBG2(2,
                         "advansys_detect: slotFound %d, busNumber %d\n",
                         pciDevice.slotFound, pciDevice.busNumber);
@@ -4351,31 +4659,69 @@
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
-            case ASC_IS_PCI:
-                while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
-                    if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
-                         pci_device_id[pci_device_id_cnt], pci_devp)) == NULL) {
-                        pci_device_id_cnt++;
-                    } else {
-                        break;
+                if (pci_init_search == 0) {
+                    int i, j;
+
+                    pci_init_search = 1;
+
+                    /* Find all PCI cards. */
+                    while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
+                        if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
+                            pci_device_id[pci_device_id_cnt], pci_devp)) ==
+                            NULL) {
+                            pci_device_id_cnt++;
+                        } else {
+                            pci_devicep[pci_card_cnt_max++] = pci_devp;
+                        }
+                    }
+
+                    /*
+                     * Sort PCI cards in ascending order by PCI Bus, Slot,
+                     * and Device Number.
+                     */
+                    for (i = 0; i < pci_card_cnt_max - 1; i++)
+                    {
+                        for (j = i + 1; j < pci_card_cnt_max; j++) {
+                            if ((pci_devicep[j]->bus->number <
+                                 pci_devicep[i]->bus->number) ||
+                                ((pci_devicep[j]->bus->number ==
+                                  pci_devicep[i]->bus->number) &&
+                                  (pci_devicep[j]->devfn <
+                                   pci_devicep[i]->devfn))) {
+                                pci_devp = pci_devicep[i];
+                                pci_devicep[i] = pci_devicep[j];
+                                pci_devicep[j] = pci_devp;
+                            }
+                        }
                     }
+
+                    pci_card_cnt = 0;
+                } else {
+                    pci_card_cnt++;
                 }
-                if (pci_devp == NULL) {
+
+                if (pci_card_cnt == pci_card_cnt_max) {
                     iop = 0;
                 } else {
+                    pci_devp = pci_devicep[pci_card_cnt];
+
                     ASC_DBG2(2,
                         "advansys_detect: devfn %d, bus number %d\n",
                         pci_devp->devfn, pci_devp->bus->number);
-                    iop = pci_devp->resource[0].start;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
+                    iop = pci_devp->base_address[0] & PCI_IOADDRESS_MASK;
+#else /* version >= v2.3.13 */ 
+                    iop = pci_devp->resource[1].start & PCI_IOADDRESS_MASK;
+#endif /* version >= v2.3.13 */ 
                     ASC_DBG2(1,
                         "advansys_detect: vendorID %X, deviceID %X\n",
                         pci_devp->vendor, pci_devp->device);
                     ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
                         iop, pci_devp->irq);
                 }
-                break;
 #endif /* CONFIG_PCI */
 #endif /* version >= v2.1.93 */ 
+                break;
 
             default:
                 ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
@@ -4418,14 +4764,18 @@
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
             if (asc_bus[bus] == ASC_IS_PCI &&
-                 pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) {
+                (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300 ||
+                 pciConfig.deviceID == ASC_PCI_DEVICE_ID_2500))
+            {
                 boardp->flags |= ASC_IS_WIDE_BOARD;
             }
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
             if (asc_bus[bus] == ASC_IS_PCI &&
-                 pci_devp->device == ASC_PCI_DEVICE_ID_2300) {
+                (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
+                 pci_devp->device == ASC_PCI_DEVICE_ID_2500))
+            {
                 boardp->flags |= ASC_IS_WIDE_BOARD;
             }
 #endif /* CONFIG_PCI */
@@ -4445,7 +4795,34 @@
                 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
                 adv_dvc_varp->drv_ptr = (ulong) boardp;
                 adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
-                adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback;
+                adv_dvc_varp->isr_callback = adv_isr_callback;
+                adv_dvc_varp->async_callback = adv_async_callback;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
+#ifdef ASC_CONFIG_PCI
+                if (pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300)
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+                } else
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+                }
+#endif /* ASC_CONFIG_PCI */
+#else /* version >= v2.1.93 */ 
+#ifdef CONFIG_PCI
+                if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+                } else
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+                }
+#endif /* CONFIG_PCI */
+#endif /* version >= v2.1.93 */ 
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
                 adv_dvc_varp->iop_base = iop;
@@ -4461,39 +4838,61 @@
                  * PCI register base address will not cross a page
                  * boundary.
                  */
+                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                {
+                    iolen = ADV_3550_IOLEN;
+                } else {
+                    iolen = ADV_38C0800_IOLEN;
+                }
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
                 pci_memory_address = pciConfig.baseAddress[1];
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+                    pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
 "advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
-                   boardp->id, pci_memory_address, ADV_CONDOR_IOLEN);
+                   boardp->id, pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
                    continue;
                 }
+                ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+                    (ulong) boardp->ioremap_addr);
                 adv_dvc_varp->iop_base = (AdvPortAddr)
                     (boardp->ioremap_addr +
                      (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+                ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+                    adv_dvc_varp->iop_base);
 #endif /* ASC_CONFIG_PCI */
 #else /* version >= v2.1.93 */ 
 #ifdef CONFIG_PCI
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,13)
+                pci_memory_address = pci_devp->base_address[1];
+#else /* version >= v2.3.13 */ 
                 pci_memory_address = pci_devp->resource[1].start;
+#endif /* version >= v2.3.13 */ 
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: %lu\n",
+                    pci_memory_address);
                 if ((boardp->ioremap_addr =
                     ioremap(pci_memory_address & PAGE_MASK,
                          PAGE_SIZE)) == 0) {
                    ASC_PRINT3(
 "advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
-                   boardp->id, pci_memory_address, ADV_CONDOR_IOLEN);
+                   boardp->id, pci_memory_address, iolen);
                    scsi_unregister(shp);
                    asc_board_count--;
                    continue;
                 }
+                ASC_DBG1(1, "advansys_detect: ioremap_addr: %lx\n",
+                    (ulong) boardp->ioremap_addr);
                 adv_dvc_varp->iop_base = (AdvPortAddr)
                     (boardp->ioremap_addr +
                      (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+                ASC_DBG1(1, "advansys_detect: iop_base: %lx\n",
+                    adv_dvc_varp->iop_base);
 #endif /* CONFIG_PCI */
 #endif /* version >= v2.1.93 */ 
 #endif /* version >= v1,3,0 */
@@ -4505,6 +4904,9 @@
                  * displayed.
                  */
                 boardp->ioport = iop;
+
+                ASC_DBG2(1, "iopb_chip_id_1 %x, iopw_chip_id_0 %x\n",
+                    (ushort) inp(iop + 1), (ushort) inpw(iop));
             }
 
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
@@ -4586,9 +4988,9 @@
                 shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine;
                 adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
                 adv_dvc_varp->cfg->pci_slot_info =
-                ASC_PCI_MKID(pciDevice.busNumber,
-                    pciDevice.slotFound,
-                    pciDevice.devFunc);
+                    ASC_PCI_MKID(pciDevice.busNumber,
+                        pciDevice.slotFound,
+                        pciDevice.devFunc);
                 shp->unchecked_isa_dma = FALSE;
                 share_irq = TRUE;
 #endif /* ASC_CONFIG_PCI */
@@ -4597,9 +4999,9 @@
                 shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
                 adv_dvc_varp->cfg->pci_device_id = pci_devp->device;
                 adv_dvc_varp->cfg->pci_slot_info =
-                ASC_PCI_MKID(pci_devp->bus->number,
-                    PCI_SLOT(pci_devp->devfn),
-                    PCI_FUNC(pci_devp->devfn));
+                    ASC_PCI_MKID(pci_devp->bus->number,
+                        PCI_SLOT(pci_devp->devfn),
+                        PCI_FUNC(pci_devp->devfn));
                 shp->unchecked_isa_dma = FALSE;
                 share_irq = TRUE;
 #endif /* CONFIG_PCI */
@@ -4616,7 +5018,7 @@
                   * longer be used. If the bus_type field must be
                   * referenced only use the bit-wise AND operator "&".
                   */
-                 ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+                ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
                 switch(ret = AscInitGetConfig(asc_dvc_varp)) {
                 case 0:    /* No error */
                     break;
@@ -4776,30 +5178,62 @@
                     shp->irq = asc_dvc_varp->irq_no;
                 }
             } else {
-
-                ADVEEP_CONFIG *ep;
+                ADVEEP_3550_CONFIG      *ep_3550;
+                ADVEEP_38C0800_CONFIG   *ep_38C0800;
 
                 /*
                  * Save Wide EEP Configuration Information.
                  */
-                ep = &boardp->eep_config.adv_eep;
-
-                ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
-                ep->max_host_qng = adv_dvc_varp->max_host_qng;
-                ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
-                ep->termination = adv_dvc_varp->cfg->termination;
-                ep->disc_enable = adv_dvc_varp->cfg->disc_enable;
-                ep->bios_ctrl = adv_dvc_varp->bios_ctrl;
-                ep->wdtr_able = adv_dvc_varp->wdtr_able;
-                ep->sdtr_able = adv_dvc_varp->sdtr_able;
-                ep->ultra_able = adv_dvc_varp->ultra_able;
-                ep->tagqng_able = adv_dvc_varp->tagqng_able;
-                ep->start_motor = adv_dvc_varp->start_motor;
-                ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
-                ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait;
-                ep->serial_number_word1 = adv_dvc_varp->cfg->serial1;
-                ep->serial_number_word2 = adv_dvc_varp->cfg->serial2;
-                ep->serial_number_word3 = adv_dvc_varp->cfg->serial3;
+                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                {
+                    ep_3550 = &boardp->eep_config.adv_3550_eep;
+
+                    ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_3550->termination = adv_dvc_varp->cfg->termination;
+                    ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
+                    ep_3550->ultra_able = adv_dvc_varp->ultra_able;
+                    ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_3550->start_motor = adv_dvc_varp->start_motor;
+                    ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
+                    ep_3550->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_3550->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_3550->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                } else
+                {
+                    ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+
+                    ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_38C0800->termination_lvd =
+                        adv_dvc_varp->cfg->termination;
+                    ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+                    ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+                    ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+                    ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C0800->start_motor = adv_dvc_varp->start_motor;
+                    ep_38C0800->scsi_reset_delay =
+                        adv_dvc_varp->scsi_reset_wait;
+                    ep_38C0800->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_38C0800->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_38C0800->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                }
 
                 /*
                  * Set the adapter's target id bit in the 'init_tidmask' field.
@@ -4842,7 +5276,7 @@
                  * Memory Mapped I/O.
                  */
                 shp->io_port = iop;
-                shp->n_io_port = ADV_CONDOR_IOLEN;
+                shp->n_io_port = iolen;
 
                 shp->this_id = adv_dvc_varp->chip_scsi_id;
 
@@ -5065,18 +5499,31 @@
                         warn_code, err_code);
                 }
             } else {
+                ADV_CARR_T      *carrp;
                 int             req_cnt;
                 adv_req_t       *reqp = NULL;
-                int             sg_cnt;
+                int             sg_cnt = 0;
                 adv_sgblk_t     *sgp = NULL;
 
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+                carrp = (ADV_CARR_T *) &adv_carr_buf[0];
                 req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
                 sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
                 reqp = (adv_req_t *) &adv_req_buf[0];
                 sgp = (adv_sgblk_t *) &adv_sgblk_buf[0];
 #else /* version >= v1.3.0 */
                 /*
+                 * Allocate buffer carrier structures.
+                 */
+                carrp =
+                    (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
+                ASC_DBG1(1, "advansys_detect: carrp %x\n", (unsigned) carrp);
+
+                if (carrp == NULL) {
+                    goto kmalloc_error;
+                }
+
+                /*
                  * Allocate up to 'max_host_qng' request structures for
                  * the Wide board.
                  */
@@ -5094,6 +5541,10 @@
                         break;
                     }
                 }
+                if (reqp == NULL)
+                {
+                    goto kmalloc_error;
+                }
 
                 /*
                  * Allocate up to ADV_TOT_SG_LIST request structures for
@@ -5112,19 +5563,27 @@
                         break;
                     }
                 }
-#endif /* version >= v1.3.0 */
 
                 /*
                  * If no request structures or scatter-gather structures could
                  * be allocated, then return an error. Otherwise continue with
                  * initialization.
                  */
-                if (reqp == NULL) {
+    kmalloc_error:
+                if (carrp == NULL)
+                {
+                    ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() carrier buffer.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else if (reqp == NULL) {
+                    kfree(carrp);
                     ASC_PRINT1(
 "advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
                         boardp->id);
                     err_code = ADV_ERROR;
                 } else if (sgp == NULL) {
+                    kfree(carrp);
                     kfree(reqp);
                     ASC_PRINT1(
 "advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n",
@@ -5132,6 +5591,9 @@
                     err_code = ADV_ERROR;
                 } else {
                     
+                    /* Save carrier buffer pointer. */
+                    boardp->orig_carrp = carrp;
+
                     /*
                      * Save original pointer for kfree() in case the
                      * driver is built as a module and can be unloaded.
@@ -5139,6 +5601,15 @@
                     boardp->orig_reqp = reqp;
 
                     /*
+                     * Save original pointer for kfree() in case the
+                     * driver is built as a module and can be unloaded.
+                     */
+                    boardp->orig_sgblkp = sgp;
+#endif /* version >= v1.3.0 */
+
+                    adv_dvc_varp->carrier_buf = carrp;
+
+                    /*
                      * Point 'adv_reqp' to the request structures and
                      * link them together.
                      */
@@ -5150,12 +5621,6 @@
                     boardp->adv_reqp = &reqp[0];
 
                     /*
-                     * Save original pointer for kfree() in case the
-                     * driver is built as a module and can be unloaded.
-                     */
-                    boardp->orig_sgblkp = sgp;
-
-                    /*
                      * Point 'adv_sgblkp' to the request structures and
                      * link them together.
                      */
@@ -5166,24 +5631,37 @@
                     }
                     boardp->adv_sgblkp = &sgp[0];
 
-                    ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n");
-                    warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+                    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                    {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc3550Driver()\n");
+                        warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+                    } else {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc38C0800Driver()\n");
+                        warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
+                    }
                     err_code = adv_dvc_varp->err_code;
 
                     if (warn_code || err_code) {
                         ASC_PRINT3(
-"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n",
+"AdvInitAsc3550/38C0800Driver: board %d: error: warn %x, error %x\n",
                             boardp->id, warn_code, adv_dvc_varp->err_code);
                     }
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
                 }
+#endif /* version >= v1,3,0 */
             }
 
             if (err_code != 0) {
                 release_region(shp->io_port, shp->n_io_port);
-                if (ASC_WIDE_BOARD(boardp)) {
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+                if (ASC_WIDE_BOARD(boardp)) {
                     iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
+                    if (boardp->orig_carrp) {
+                        kfree(boardp->orig_carrp);
+                        boardp->orig_carrp = NULL;
+                    }
                     if (boardp->orig_reqp) {
                         kfree(boardp->orig_reqp);
                         boardp->orig_reqp = boardp->adv_reqp = NULL;
@@ -5193,6 +5671,7 @@
                         boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
                     }
                 }
+#endif /* version >= v1,3,0 */
                 if (shp->dma_channel != NO_ISA_DMA) {
                     free_dma(shp->dma_channel);
                 }
@@ -5237,10 +5716,13 @@
         free_dma(shp->dma_channel);
     }
     release_region(shp->io_port, shp->n_io_port);
-    if (ASC_WIDE_BOARD(boardp)) {
 #if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+    if (ASC_WIDE_BOARD(boardp)) {
         iounmap(boardp->ioremap_addr);
-#endif /* version >= v1,3,0 */
+        if (boardp->orig_carrp) {
+            kfree(boardp->orig_carrp);
+            boardp->orig_carrp = NULL;
+        }
         if (boardp->orig_reqp) {
             kfree(boardp->orig_reqp);
             boardp->orig_reqp = boardp->adv_reqp = NULL;
@@ -5250,7 +5732,6 @@
             boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
         }
     }
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
     ASC_ASSERT(boardp->prtbuf != NULL);
     kfree(boardp->prtbuf);
 #endif /* version >= v1.3.0 */
@@ -5276,6 +5757,8 @@
     ASC_DVC_VAR     *asc_dvc_varp;
     ADV_DVC_VAR     *adv_dvc_varp;
     char            *busname;
+    int             iolen;
+    char            *widename = NULL;
 
     boardp = ASC_BOARDP(shp);
     if (ASC_NARROW_BOARD(boardp)) {
@@ -5342,21 +5825,31 @@
          * I/O address is displayed through the driver /proc file.
          */
         adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+        if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+        {
+            iolen = ADV_3550_IOLEN;
+            widename = "Ultra-Wide";
+        } else {
+            iolen = ADV_38C0800_IOLEN;
+            widename = "Ultra2-Wide";
+        }
         if (boardp->bios_signature == 0x55AA) {
             sprintf(info,
-"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u",
+"AdvanSys SCSI %s: PCI %s: BIOS %X/%X, IO %X/%X, IRQ %u",
                 ASC_VERSION,
+                widename,
                 boardp->bios_codeseg << 4,
                 boardp->bios_codelen > 0 ?
                 (boardp->bios_codelen << 9) - 1 : 0,
-                (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1,
+                (unsigned) boardp->ioport, iolen - 1,
                 shp->irq);
         } else {
             sprintf(info,
-"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u",
+"AdvanSys SCSI %s: PCI %s: IO %X/%X, IRQ %u",
                 ASC_VERSION,
+                widename,
                 (unsigned) boardp->ioport,
-                (ADV_CONDOR_IOLEN - 1),
+                (iolen - 1),
                 shp->irq);
         }
     }
@@ -5579,7 +6072,7 @@
                 asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
                 scp->result = HOST_BYTE(DID_ABORT);
 
-                /* sti(); - FIXME!!! Enable interrupts for AscAbortSRB() must be careful about io_lock. */
+                /* sti(); XXX */ /* Enable interrupts for AscAbortSRB(). */
                 ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
                     (unsigned) scp);
                 switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
@@ -5607,22 +6100,23 @@
                 adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
                 scp->result = HOST_BYTE(DID_ABORT);
 
-                ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n",
+                ASC_DBG1(1, "advansys_abort: before AdvAbortQueue(), scp %x\n",
                     (unsigned) scp);
-                switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) {
+#if 0 /* XXX */
+                switch (AdvAbortQueue(adv_dvc_varp, (ulong) XXX)) {
                 case ASC_TRUE:
                     /* asc_isr_callback() will be called */
-                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n");
+                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() TRUE\n");
                     ret = SCSI_ABORT_PENDING;
                     break;
                 case ASC_FALSE:
                     /* Request has apparently already completed. */
-                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n");
+                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() FALSE\n");
                     ret = SCSI_ABORT_NOT_RUNNING;
                     break;
                 case ASC_ERROR:
                 default:
-                    ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n");
+                    ASC_DBG(1, "advansys_abort: AdvAbortQueue() ERROR\n");
                     ret = SCSI_ABORT_ERROR;
                     break;
                 }
@@ -5631,6 +6125,10 @@
                  * been processed by calling AdvISR().
                  */
                 (void) AdvISR(adv_dvc_varp);
+#else /* XXX */
+                (void) AdvResetChipAndSB(adv_dvc_varp);
+                ret = SCSI_ABORT_SUCCESS;
+#endif /* XXX */
             }
 
             /*
@@ -5644,7 +6142,6 @@
                 scp_found = asc_rmqueue(&boardp->done, scp);
                 ASC_ASSERT(scp_found == ASC_TRUE);
             }
-
         } else {
             /*
              * The command was not found on the active or waiting queues.
@@ -5786,8 +6283,13 @@
         }
         scp->result = HOST_BYTE(DID_ERROR);
         ret = SCSI_RESET_ERROR;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
     } else if (time_after_eq(jiffies, boardp->last_reset) &&
                time_before(jiffies, boardp->last_reset + (10 * HZ))) {
+#else /* version < v2.1.0 */
+    } else if (jiffies >= boardp->last_reset &&
+               jiffies < (boardp->last_reset + (10 * HZ))) {
+#endif /* version < v2.1.0 */
         /*
          * Don't allow a reset to be attempted within 10 seconds
          * of the last reset.
@@ -5849,9 +6351,9 @@
                  * Reset the target's SCSI bus.
                  */
                 ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
-                /* sti();    FIXME!!! Enable interrupts for AscResetSB(). */
+                /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
                 status = AscResetSB(asc_dvc_varp);
-                /* cli();    FIXME!!! */
+                /* cli(); XXX */
                 switch (status) {
                 case ASC_TRUE:
                     ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
@@ -5874,9 +6376,9 @@
                 ASC_DBG1(1,
                     "advansys_reset: before AscResetDevice(), target %d\n",
                     scp->target);
-                /* sti();    FIXME!!! Enable interrupts for AscResetDevice(). */
+                /* sti(); XXX */ /* Enable interrupts for AscResetDevice(). */
                 status = AscResetDevice(asc_dvc_varp, scp->target);
-                /* cli();    FIXME!!! */
+                /* cli(); XXX */
 
                 switch (status) {
                 case ASC_TRUE:
@@ -5888,9 +6390,9 @@
                 default:
                     ASC_DBG(1,
 "advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
-                    /* sti();   FIXME!!! Enable interrupts for AscResetSB(). */
+                    /* sti(); XXX */ /* Enable interrupts for AscResetSB(). */
                     status = AscResetSB(asc_dvc_varp);
-                    /* cli(); */
+                    /* cli(); XXX */
                     switch (status) {
                     case ASC_TRUE:
                         ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
@@ -5923,15 +6425,16 @@
                 /*
                  * Reset the target's SCSI bus.
                  */
-                ASC_DBG(1, "advansys_reset: before AdvResetSB()\n");
-                switch (AdvResetSB(adv_dvc_varp)) {
+                ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+                switch (AdvResetChipAndSB(adv_dvc_varp)) {
                 case ASC_TRUE:
-                    ASC_DBG(1, "advansys_reset: AdvResetSB() success\n");
+                    ASC_DBG(1,
+                        "advansys_reset: AdvResetChipAndSB() success\n");
                     ret = SCSI_RESET_SUCCESS;
                     break;
                 case ASC_FALSE:
                 default:
-                    ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n");
+                    ASC_DBG(1, "advansys_reset: AdvResetChipAndSB() failed\n");
                     ret = SCSI_RESET_ERROR;
                     break;
                 }
@@ -5960,16 +6463,18 @@
                 case ASC_FALSE:
                 default:
                     ASC_DBG(1,
-"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n");
+"advansys_reset: AdvResetDevice() failed; Calling AdvResetChipAndSB()\n");
                     
-                    switch (AdvResetSB(adv_dvc_varp)) {
+                    switch (AdvResetChipAndSB(adv_dvc_varp)) {
                     case ASC_TRUE:
-                        ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n");
+                        ASC_DBG(1,
+                            "advansys_reset: AdvResetChipAndSB() TRUE\n");
                         ret = SCSI_RESET_SUCCESS;
                         break;
                     case ASC_FALSE:
                     default:
-                        ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n");
+                        ASC_DBG(1,
+                            "advansys_reset: AdvResetChipAndSB() ERROR\n");
                         ret = SCSI_RESET_ERROR;
                         break;
                     }
@@ -6188,8 +6693,10 @@
  * ints[2] - second argument
  * ...
  */
-void ASC_INIT
+ASC_INITFUNC(
+void,
 advansys_setup(char *str, int *ints)
+)
 {
     int    i;
 
@@ -6541,27 +7048,6 @@
              */
             boardp->reqcnt[scp->target]++;
 
-#if ASC_QUEUE_FLOW_CONTROL
-            /*
-             * Conditionally increment the device queue depth.
-             *
-             * If no error occurred and there have been 100 consecutive
-             * successful requests and the current queue depth is less
-             * than the maximum queue depth, then increment the current
-             * queue depth.
-             */
-            if (boardp->nerrcnt[scp->target]++ > 100) {
-                boardp->nerrcnt[scp->target] = 0;
-                if (device != NULL &&
-                    (device->queue_curr_depth < device->queue_depth) &&
-                    (!(boardp->queue_full &
-                       ADV_TID_TO_TIDMASK(scp->target)) ||
-                     (boardp->queue_full_cnt[scp->target] >
-                      device->queue_curr_depth))) {
-                    device->queue_curr_depth++;
-                }
-            }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             asc_enqueue(&boardp->active, scp, ASC_BACK);
             ASC_DBG(1,
                 "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
@@ -6569,26 +7055,12 @@
         case ASC_BUSY:
             /* Caller must enqueue request and retry later. */
             ASC_STATS(scp->host, exe_busy);
-#if ASC_QUEUE_FLOW_CONTROL
-            /*
-             * Clear consecutive no error counter and if possible decrement
-             * queue depth.
-             */
-            boardp->nerrcnt[scp->target] = 0;
-            if (device != NULL && device->queue_curr_depth > 1) {
-                device->queue_curr_depth--;
-            }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             break;
         case ASC_ERROR:
             ASC_PRINT2(
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
                 boardp->id, asc_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_error);
-#if ASC_QUEUE_FLOW_CONTROL
-            /* Clear consecutive no error counter. */
-            boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
             break;
@@ -6597,10 +7069,6 @@
 "asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
                 boardp->id, asc_dvc_varp->err_code);
             ASC_STATS(scp->host, exe_unknown);
-#if ASC_QUEUE_FLOW_CONTROL
-            /* Clear consecutive no error counter. */
-            boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
             scp->result = HOST_BYTE(DID_ERROR);
             asc_enqueue(&boardp->done, scp, ASC_BACK);
             break;
@@ -6868,7 +7336,6 @@
     scsiqp->target_id = scp->target;
     scsiqp->target_lun = scp->lun;
 
-    scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0];
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
     scsiqp->sense_addr = (ulong) &scp->sense_buffer[0];
 #else /* version >= v2.0.0 */
@@ -6994,7 +7461,7 @@
     ADV_SG_BLOCK        *sg_block;              /* virtual address of a SG */
     ulong               sg_block_next_addr;     /* block and its next */
     ulong               sg_block_physical_addr;
-    int                 sg_block_index, i;      /* how many SG entries */
+    int                 i;
     struct scatterlist  *slp;
     int                 sg_elem_cnt;
 
@@ -7013,10 +7480,8 @@
                    sg_block_physical_addr);
     scsiqp->sg_real_addr = sg_block_physical_addr;
 
-    sg_block_index = 0;
     do
     {
-        sg_block->first_entry_no = sg_block_index;
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
@@ -7030,21 +7495,19 @@
 
             if (--sg_elem_cnt == 0)
             {   /* last entry, get out */
-                scsiqp->sg_entry_cnt = sg_block_index + i + 1;
-                sg_block->last_entry_no = sg_block_index + i;
+                sg_block->sg_cnt = i + 1;
                 sg_block->sg_ptr = 0L;    /* next link = NULL */
                 return ADV_SUCCESS;
             }
             slp++;
         } 
+        sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
         sg_block_next_addr += sizeof(ADV_SG_BLOCK);
         sg_block_physical_addr += sizeof(ADV_SG_BLOCK);
         ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
                        sg_block_physical_addr);
 
-        sg_block_index += NO_OF_SG_PER_BLOCK;
         sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr;
-        sg_block->last_entry_no = sg_block_index - 1;
         sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */
     }
     while (1);
@@ -7270,7 +7733,7 @@
      * command that has been completed.
      *
      * Note: The adv_req_t request structure and adv_sgblk_t structure,
-     * if any, * dropped, because a board structure pointer can not be
+     * if any, are dropped, because a board structure pointer can not be
      * determined.
      */
     scp = reqp->cmndp;
@@ -7443,13 +7906,53 @@
     return;
 }
 
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
-#ifdef ASC_CONFIG_PCI
 /*
- * Search for an AdvanSys PCI device in the PCI configuration space.
+ * adv_async_callback() - Adv Library asynchronous event callback function.
  */
-STATIC int ASC_INIT
-asc_srch_pci_dev(PCI_DEVICE *pciDevice)
+STATIC void
+adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+{
+    switch (code)
+    {
+    case ADV_ASYNC_SCSI_BUS_RESET_DET:
+        /*
+         * The firmware detected a SCSI Bus reset.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+        break;
+
+    case ADV_ASYNC_RDMA_FAILURE:
+        /*
+         * Handle RDMA failure by resetting the SCSI Bus and
+         * possibly the chip if it is unresponsive. Log the error
+         * with a unique code.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
+        AdvResetChipAndSB(adv_dvc_varp);
+        break;
+
+    case ADV_HOST_SCSI_BUS_RESET:
+        /*
+         * Host generated SCSI bus reset occurred.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
+        break;
+
+    default:
+        ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
+        break;
+    }
+}
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
+#ifdef ASC_CONFIG_PCI
+/*
+ * Search for an AdvanSys PCI device in the PCI configuration space.
+ */
+ASC_INITFUNC(
+STATIC int,
+asc_srch_pci_dev(PCI_DEVICE *pciDevice)
+)
 {
     int                        ret = PCI_DEVICE_NOT_FOUND;
 
@@ -7486,8 +7989,10 @@
 /*
  * Determine the access method to be used for 'pciDevice'.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 asc_scan_method(void)
+)
 {
     ushort      data;
     PCI_DATA    pciData;
@@ -7516,8 +8021,10 @@
  *
  * Return PCI_DEVICE_FOUND if found, otherwise return PCI_DEVICE_NOT_FOUND.
  */
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 asc_pci_find_dev(PCI_DEVICE *pciDevice)
+)
 {
     PCI_DATA    pciData;
     ushort      vendorid, deviceid;
@@ -7542,7 +8049,8 @@
                 ((deviceid == ASC_PCI_DEVICE_ID_1100) ||
                  (deviceid == ASC_PCI_DEVICE_ID_1200) ||
                  (deviceid == ASC_PCI_DEVICE_ID_1300) ||
-                 (deviceid == ASC_PCI_DEVICE_ID_2300))) {
+                 (deviceid == ASC_PCI_DEVICE_ID_2300) ||
+                 (deviceid == ASC_PCI_DEVICE_ID_2500))) {
                 pciDevice->slotFound = lslot;
                 ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
                 return PCI_DEVICE_FOUND;
@@ -7566,8 +8074,10 @@
 /*
  * Read PCI configuration data into 'pciConfig'.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 asc_get_pci_cfg(PCI_DEVICE *pciDevice, PCI_CONFIG_SPACE *pciConfig)
+)
 {
     PCI_DATA    pciData;
     uchar       counter;
@@ -7596,8 +8106,10 @@
  *
  * The configuration mechanism is checked for the correct access method.
  */
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 asc_get_cfg_word(PCI_DATA *pciData)
+)
 {
     ushort   tmp;
     ulong    address;
@@ -7626,7 +8138,7 @@
         /* set for type 1 cycle, if needed */
         outp(0xCFA, pciData->bus);
         /* set the function number */
-        outp(0xCF8, 0x10 | (pciData->func << 1)) ;
+        outp(0xCF8, 0x10 | (pciData->func << 1));
 
         /*
          * Read the configuration space type 2 locations.
@@ -7677,8 +8189,10 @@
  *
  * The configuration mechanism is checked for the correct access method.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 asc_get_cfg_byte(PCI_DATA *pciData)
+)
 {
     uchar tmp;
     ulong address;
@@ -7755,8 +8269,10 @@
 /*
  * Write a byte to the PCI configuration space.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data)
+)
 {
     ulong tmpl;
     ulong address;
@@ -8498,19 +9014,29 @@
 STATIC int
 asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
 {
-    asc_board_t        *boardp;
-    ADV_DVC_VAR        *adv_dvc_varp;
-    int                leftlen;
-    int                totlen;
-    int                len;
-    int                i;
-    char               *termstr;
-    uchar              serialstr[13];
-    ADVEEP_CONFIG      *ep;
+    asc_board_t                 *boardp;
+    ADV_DVC_VAR                 *adv_dvc_varp;
+    int                         leftlen;
+    int                         totlen;
+    int                         len;
+    int                         i;
+    char                        *termstr;
+    uchar                       serialstr[13];
+    ADVEEP_3550_CONFIG          *ep_3550 = NULL;
+    ADVEEP_38C0800_CONFIG       *ep_38C0800 = NULL;
+    ushort                      word;
+    ushort                      *wordp;
+    ushort                      sdtr_speed = 0;
 
     boardp = ASC_BOARDP(shp);
     adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-    ep = &boardp->eep_config.adv_eep;
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        ep_3550 = &boardp->eep_config.adv_3550_eep;
+    } else
+    {
+        ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+    }
 
     leftlen = cplen;
     totlen = len = 0;
@@ -8519,8 +9045,15 @@
 "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
     ASC_PRT_NEXT();
 
-    if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) ==
-        ASC_TRUE) {
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        wordp = &ep_3550->serial_number_word1;
+    } else
+    {
+        wordp = &ep_38C0800->serial_number_word1;
+    }
+
+    if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
         len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
         ASC_PRT_NEXT();
     } else {
@@ -8529,12 +9062,29 @@
         ASC_PRT_NEXT();
     }
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-        ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng);
-    ASC_PRT_NEXT();
-
-    switch (ep->termination) {
+            ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
+            ep_3550->max_dvc_qng);
+        ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+            ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
+            ep_38C0800->max_dvc_qng);
+        ASC_PRT_NEXT();
+    }
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->termination;
+    } else
+    {
+        word = ep_38C0800->termination_lvd;
+    }
+    switch (word) {
         case 1:
             termstr = "Low Off/High Off";
             break;
@@ -8550,10 +9100,19 @@
             break;
     }
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " termination: %u (%s), bios_ctrl: %x\n",
-        ep->termination, termstr, ep->bios_ctrl);
-    ASC_PRT_NEXT();
+            ep_3550->termination, termstr, ep_3550->bios_ctrl);
+        ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: %x\n",
+            ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
+        ASC_PRT_NEXT();
+    }
 
     len = asc_prt_line(cp, leftlen,
 " Target ID:           ");
@@ -8565,72 +9124,150 @@
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->disc_enable;
+    } else
+    {
+        word = ep_38C0800->disc_enable;
+    }
     len = asc_prt_line(cp, leftlen,
 " Disconnects:         ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->tagqng_able;
+    } else
+    {
+        word = ep_38C0800->tagqng_able;
+    }
     len = asc_prt_line(cp, leftlen,
 " Command Queuing:     ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->start_motor;
+    } else
+    {
+        word = ep_38C0800->start_motor;
+    }
     len = asc_prt_line(cp, leftlen,
 " Start Motor:         ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " Synchronous Transfer:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            len = asc_prt_line(cp, leftlen, " %c",
+                (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
         ASC_PRT_NEXT();
     }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
 " Ultra Transfer:      ");
     ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            len = asc_prt_line(cp, leftlen, " %c",
+                (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
         ASC_PRT_NEXT();
     }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->wdtr_able;
+    } else
+    {
+        word = ep_38C0800->wdtr_able;
+    }
     len = asc_prt_line(cp, leftlen,
 " Wide Transfer:       ");
     ASC_PRT_NEXT();
     for (i = 0; i <= ADV_MAX_TID; i++) {
         len = asc_prt_line(cp, leftlen, " %c",
-            (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer Speed (Mhz):\n  ");
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            char *speed_str;
+
+            if (i == 0)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed1;
+            } else if (i == 4)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed2;
+            } else if (i == 8)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed3;
+            } else if (i == 12)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed4;
+            }
+            switch (sdtr_speed & ADV_MAX_TID)
+            {
+                case 0:  speed_str = "Off"; break;
+                case 1:  speed_str = "  5"; break;
+                case 2:  speed_str = " 10"; break;
+                case 3:  speed_str = " 20"; break;
+                case 4:  speed_str = " 40"; break;
+                case 5:  speed_str = " 80"; break;
+                default: speed_str = "Unk"; break;
+            }
+            len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+            ASC_PRT_NEXT();
+            if (i == 7)
+            {
+                len = asc_prt_line(cp, leftlen, "\n  ");
+                ASC_PRT_NEXT();
+            }
+            sdtr_speed >>= 4;
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
+
     return totlen;
 }
 
@@ -8728,46 +9365,6 @@
     }
 #endif /* version >= v1.3.89 */
 
-#if ASC_QUEUE_FLOW_CONTROL
-    if (ASC_NARROW_BOARD(boardp)) {
-        len = asc_prt_line(cp, leftlen, " queue_curr_depth:");
-        ASC_PRT_NEXT();
-        /* Use ASC_MAX_TID for Narrow Board. */
-        for (i = 0; i <= ASC_MAX_TID; i++) {
-            if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                continue;
-            }
-            if (boardp->device[i] == NULL) {
-                continue;
-            }
-            len = asc_prt_line(cp, leftlen, " %d:%d",
-                i, boardp->device[i]->queue_curr_depth);
-            ASC_PRT_NEXT();
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-
-        len = asc_prt_line(cp, leftlen, " queue_count:");
-        ASC_PRT_NEXT();
-        /* Use ASC_MAX_TID for Narrow Board. */
-        for (i = 0; i <= ASC_MAX_TID; i++) {
-            if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
-                ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-                continue;
-            }
-            if (boardp->device[i] == NULL) {
-                continue;
-            }
-            len = asc_prt_line(cp, leftlen, " %d:%d",
-                i, boardp->device[i]->queue_count);
-            ASC_PRT_NEXT();
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-    }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
-
     return totlen;
 }
 
@@ -8786,16 +9383,19 @@
 asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
 {
     asc_board_t            *boardp;
+    int                    chip_scsi_id;
     int                    leftlen;
     int                    totlen;
     int                    len;
     ASC_DVC_VAR            *v;
     ASC_DVC_CFG            *c;
     int                    i;
+    int                    renegotiate = 0;
 
     boardp = ASC_BOARDP(shp);
     v = &boardp->dvc_var.asc_dvc_var;
     c = &boardp->dvc_cfg.asc_dvc_cfg;
+    chip_scsi_id = c->chip_scsi_id;
 
     leftlen = cplen;
     totlen = len = 0;
@@ -8824,11 +9424,11 @@
 " Command Queuing:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%c",
+        len = asc_prt_line(cp, leftlen, " %X:%c",
             i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
@@ -8840,11 +9440,11 @@
 " Command Queue Pending:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
+        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
@@ -8855,11 +9455,11 @@
 " Command Queue Limit:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
+        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
@@ -8870,15 +9470,15 @@
 " Command Queue Full:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
         if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
-            len = asc_prt_line(cp, leftlen, " %d:Y-%d",
+            len = asc_prt_line(cp, leftlen, " %X:Y-%d",
                 i, boardp->queue_full_cnt[i]);
         } else {
-            len = asc_prt_line(cp, leftlen, " %d:N", i);
+            len = asc_prt_line(cp, leftlen, " %X:N", i);
         }
         ASC_PRT_NEXT();
     }
@@ -8889,11 +9489,11 @@
 " Synchronous Transfer:");
     ASC_PRT_NEXT();
     for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+        if ((chip_scsi_id == i) ||
             ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
-        len = asc_prt_line(cp, leftlen, " %d:%c",
+        len = asc_prt_line(cp, leftlen, " %X:%c",
             i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
@@ -8903,26 +9503,50 @@
     for (i = 0; i <= ASC_MAX_TID; i++) {
         uchar syn_period_ix;
 
-        if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
+
+        len = asc_prt_line(cp, leftlen, "  %X:", i);
+        ASC_PRT_NEXT();
+
+        if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
+        {
+            len = asc_prt_line(cp, leftlen, " Asynchronous");
+            ASC_PRT_NEXT();
+        } else
+        {
+            syn_period_ix =
+                (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
+
+            len = asc_prt_line(cp, leftlen,
+                " Transfer Period Factor: %d (%d.%d Mhz),",
+                v->sdtr_period_tbl[syn_period_ix],
+                250 / v->sdtr_period_tbl[syn_period_ix],
+                ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
+            ASC_PRT_NEXT();
+
+            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+            ASC_PRT_NEXT();
+        }
+
         if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-            continue;
+            len = asc_prt_line(cp, leftlen, "*\n");
+            renegotiate = 1;
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, "\n");
         }
-        syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
-        len = asc_prt_line(cp, leftlen, "  %d:", i);
         ASC_PRT_NEXT();
+    }
 
+    if (renegotiate)
+    {
         len = asc_prt_line(cp, leftlen,
-            " Transfer Period Factor: %d (%d.%d Mhz),",
-            v->sdtr_period_tbl[syn_period_ix],
-            250 / v->sdtr_period_tbl[syn_period_ix],
-            ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
-        ASC_PRT_NEXT();
-
-        len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
-            boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+            " * = Re-negotiation pending before next command.\n");
         ASC_PRT_NEXT();
     }
 
@@ -8954,8 +9578,11 @@
     ushort                 chip_scsi_id;
     ushort                 lramword;
     uchar                  lrambyte;
-    ushort                 sdtr_able;
-    ushort                 period;
+    ushort                 tagqng_able;
+    ushort                 sdtr_able, wdtr_able;
+    ushort                 wdtr_done, sdtr_done;
+    ushort                 period = 0;
+    int                    renegotiate = 0;
 
     boardp = ASC_BOARDP(shp);
     v = &boardp->dvc_var.adv_dvc_var;
@@ -8972,10 +9599,10 @@
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
-" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n",
+" iop_base %lx, cable_detect: %X, err_code %u\n",
          v->iop_base,
          AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
-         v->err_code, v->idle_cmd_done);
+         v->err_code);
     ASC_PRT_NEXT();
 
     len = asc_prt_line(cp, leftlen,
@@ -8983,7 +9610,7 @@
         c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
     ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
     len = asc_prt_line(cp, leftlen,
 " Queuing Enabled:");
     ASC_PRT_NEXT();
@@ -8994,7 +9621,7 @@
         }
 
         len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
@@ -9034,7 +9661,7 @@
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword);
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
     len = asc_prt_line(cp, leftlen,
 " Wide Enabled:");
     ASC_PRT_NEXT();
@@ -9045,12 +9672,13 @@
         }
 
         len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
         ASC_PRT_NEXT();
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
     len = asc_prt_line(cp, leftlen,
 " Transfer Bit Width:");
     ASC_PRT_NEXT();
@@ -9062,9 +9690,17 @@
 
         AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
             lramword);
+
         len = asc_prt_line(cp, leftlen, " %X:%d",
             i, (lramword & 0x8000) ? 16 : 8);
         ASC_PRT_NEXT();
+
+        if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+            (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*");
+            ASC_PRT_NEXT();
+            renegotiate = 1;
+        }
     }
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
@@ -9086,6 +9722,7 @@
     len = asc_prt_line(cp, leftlen, "\n");
     ASC_PRT_NEXT();
 
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
     for (i = 0; i <= ADV_MAX_TID; i++) {
 
         AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
@@ -9093,23 +9730,67 @@
         lramword &= ~0x8000;
 
         if ((chip_scsi_id == i) ||
-            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) ||
-            (lramword == 0)) {
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
             continue;
         }
 
         len = asc_prt_line(cp, leftlen, "  %X:", i);
         ASC_PRT_NEXT();
-        
-        period = (((lramword >> 8) * 25) + 50)/4;
 
-        len = asc_prt_line(cp, leftlen,
-            " Transfer Period Factor: %d (%d.%d Mhz),",
-            period, 250/period, ASC_TENTHS(250, period));
+        if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
+        {
+            len = asc_prt_line(cp, leftlen, " Asynchronous");
+            ASC_PRT_NEXT();
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
+            ASC_PRT_NEXT();
+
+            if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
+            {
+                len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+                ASC_PRT_NEXT();
+            } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
+            {
+                len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+                ASC_PRT_NEXT();
+            } else /* 20 Mhz or below. */
+            {
+                period = (((lramword >> 8) * 25) + 50)/4;
+
+                if (period == 0) /* Should never happen. */
+                {
+                    len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
+                    ASC_PRT_NEXT();
+                } else
+                {
+                    len = asc_prt_line(cp, leftlen,
+                        "%d (%d.%d Mhz),",
+                        period, 250/period, ASC_TENTHS(250, period));
+                    ASC_PRT_NEXT();
+                }
+            }
+
+            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                lramword & 0x1F);
+            ASC_PRT_NEXT();
+        }
+
+        if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*\n");
+            renegotiate = 1;
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, "\n");
+        }
         ASC_PRT_NEXT();
+    }
 
-        len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
-            lramword & 0x1F);
+    if (renegotiate)
+    {
+        len = asc_prt_line(cp, leftlen,
+            " * = Re-negotiation pending before next command.\n");
         ASC_PRT_NEXT();
     }
 
@@ -9164,7 +9845,7 @@
 {
     va_list        args;
     int            ret;
-    char        s[ASC_PRTLINE_SIZE];
+    char           s[ASC_PRTLINE_SIZE];
 
     va_start(args, fmt);
     ret = vsprintf(s, fmt, args);
@@ -9195,8 +9876,18 @@
 STATIC void
 DvcSleepMilliSecond(ulong n)
 {
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+    ulong i;
+#endif /* version < v2.1.0 */ 
+
     ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", n);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
     mdelay(n);
+#else /* version < v2.1.0 */ 
+    for (i = 0; i < n; i++) {
+        udelay(1000);
+    }
+#endif /* version < v2.1.0 */ 
 }
 
 STATIC int
@@ -9346,10 +10037,12 @@
 /*
  * Read a PCI configuration byte.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 DvcReadPCIConfigByte(
         ASC_DVC_VAR asc_ptr_type *asc_dvc, 
         ushort offset)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9381,11 +10074,13 @@
 /*
  * Write a PCI configuration byte.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 DvcWritePCIConfigByte(
         ASC_DVC_VAR asc_ptr_type *asc_dvc, 
         ushort offset, 
         uchar  byte_data)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9412,14 +10107,16 @@
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  */
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetChipBiosAddress(
         PortAddr iop_base,
         ushort bus_type
 )
+)
 {
-    ushort  cfg_lsw ;
-    ushort  bios_addr ;
+    ushort  cfg_lsw;
+    ushort  bios_addr;
 
     /*
      * The PCI BIOS is re-located by the motherboard BIOS. Because
@@ -9433,14 +10130,14 @@
 
     if((bus_type & ASC_IS_EISA) != 0)
     {
-        cfg_lsw = AscGetEisaChipCfg(iop_base) ;
-        cfg_lsw &= 0x000F ;
+        cfg_lsw = AscGetEisaChipCfg(iop_base);
+        cfg_lsw &= 0x000F;
         bios_addr = (ushort)(ASC_BIOS_MIN_ADDR  +
-                                (cfg_lsw * ASC_BIOS_BANK_SIZE)) ;
-        return(bios_addr) ;
+                                (cfg_lsw * ASC_BIOS_BANK_SIZE));
+        return(bios_addr);
     }/* if */
 
-    cfg_lsw = AscGetChipCfgLsw(iop_base) ;
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
 
     /*
     *  ISA PnP uses the top bit as the 32K BIOS flag
@@ -9451,8 +10148,8 @@
     }/* if */
 
     bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
-            ASC_BIOS_MIN_ADDR) ;
-    return(bios_addr) ;
+            ASC_BIOS_MIN_ADDR);
+    return(bios_addr);
 }
 
 
@@ -9493,10 +10190,12 @@
 /*
  * Read a PCI configuration byte.
  */
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 DvcAdvReadPCIConfigByte(
         ADV_DVC_VAR *asc_dvc, 
         ushort offset)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9528,11 +10227,13 @@
 /*
  * Write a PCI configuration byte.
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 DvcAdvWritePCIConfigByte(
         ADV_DVC_VAR *asc_dvc, 
         ushort offset, 
         uchar  byte_data)
+)
 {
 #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,93)
 #ifdef ASC_CONFIG_PCI
@@ -9743,12 +10444,13 @@
         (unsigned) s->hostt, (unsigned) s->block);
 
     printk(
-" wish_block %d, base %x, io_port %d, n_io_port %d, irq %d, dma_channel %d,\n",
-        s->wish_block, (unsigned) s->base, s->io_port, s->n_io_port,
-        s->irq, s->dma_channel);
+" wish_block %d, base %lu, io_port %lu, n_io_port %u, irq %d,\n",
+        s->wish_block, (ulong) s->base, (ulong) s->io_port, s->n_io_port,
+        s->irq);
 
     printk(
-" this_id %d, can_queue %d,\n", s->this_id, s->can_queue);
+" dma_channel %d, this_id %d, can_queue %d,\n",
+        s->dma_channel, s->this_id, s->can_queue);
 
     printk(
 " cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
@@ -9966,15 +10668,23 @@
         (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
 
     printk(
-"  max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n",
-        (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng,
-        (unsigned) h->max_dvc_qng);
+"  max_host_qng %x, max_dvc_qng %x, carr_freelist %lxn\n",
+        (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
+        (ulong) h->carr_freelist);
+
 
     printk(
-"  no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n",
-        (unsigned) h->no_scam, (unsigned) h->tagqng_able,
-        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+"  icq_sp %lx, irq_sp %lx\n",
+        (ulong) h->icq_sp,
+        (ulong) h->irq_sp);
+
+    printk(
+"  no_scam 0x%x, tagqng_able 0x%x\n",
+        (unsigned) h->no_scam, (unsigned) h->tagqng_able);
 
+    printk(
+"  chip_scsi_id 0x%x, cfg %lx\n",
+        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
 }
 
 /*
@@ -10012,7 +10722,7 @@
 STATIC void 
 asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 {
-    int                 i;
+    int                 sg_blk_cnt;
     struct asc_sg_block *sg_ptr;
 
     printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q);
@@ -10025,6 +10735,10 @@
             q->cntl, q->data_addr, q->vdata_addr);
 
     printk(
+"  cntl 0x%x, data_addr %lx, vdata_addr %lx\n",
+            q->cntl, q->data_addr, q->vdata_addr);
+
+    printk(
 "  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
             q->data_cnt, q->sense_addr, q->sense_len);
 
@@ -10033,63 +10747,58 @@
             q->cdb_len, q->done_status, q->host_status, q->scsi_status);
 
     printk(
-"  vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n",
-            (ulong) q->vsense_addr, (ulong) q->scsiq_ptr,
-            (ulong) q->ux_wk_data_cnt);
-
-    printk(
-"  sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n",
-            (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt);
+"  sg_working_ix %x, sg_working_data_cnt %lx, reserved %u\n",
+            q->sg_working_ix, q->sg_working_data_cnt, q->reserved);
 
     printk(
-"  ux_sg_ix %u, orig_sense_len %u\n",
-            q->ux_sg_ix, q->orig_sense_len);
+"  scsiq_rptr %lx, sg_real_addr %lx, sg_list_ptr %lx\n",
+            q->scsiq_rptr, q->sg_real_addr, (ulong) q->sg_list_ptr);
 
     /* Display the request's ADV_SG_BLOCK structures. */
-    for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL;
-        sg_ptr = sg_ptr->sg_ptr, i++) {
-        /*
-         * 'sg_ptr' is a physical address. Convert it to a virtual
-         * address by indexing 'i' into the virtual address array
-         * 'sg_list_ptr'.
-         *
-         * At the end of the each iteration of the loop 'sg_ptr' is
-         * converted back into a physical address by setting 'sg_ptr'
-         *  to the next pointer 'sg_ptr->sg_ptr'.
-         */
-        sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]);
-        asc_prt_adv_sgblock(i, sg_ptr);
-    }
-}
-
-/*
- * asc_prt_adv_sgblock()
+    if (q->sg_list_ptr != NULL)
+    {
+        sg_blk_cnt = 0;
+        while (1) {
+            /*
+             * 'sg_ptr' is a physical address. Convert it to a virtual
+             * address by indexing 'sg_blk_cnt' into the virtual address
+             * array 'sg_list_ptr'.
+             *
+             * XXX - Assumes all SG physical blocks are virtually contiguous.
+             */
+            sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
+            asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+            if (sg_ptr->sg_ptr == NULL)
+            {
+                break;
+            }
+            sg_blk_cnt++;
+        }
+    }
+}
+
+/*
+ * asc_prt_adv_sgblock()
  *
  * Display an ADV_SG_BLOCK structure.
  */
 STATIC void
 asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
 {
-    int i, s;
-
-    /* Calculate starting entry number for the current block. */
-    s = sgblockno * NO_OF_SG_PER_BLOCK;
+    int i;
 
-    printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n",
-        (ulong) b, (ulong) sgblockno);
-    printk(
-"  first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n",
-        (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr);
-    ASC_ASSERT(b->first_entry_no - s >= 0);
-    ASC_ASSERT(b->last_entry_no - s >= 0);
-    ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK);
-    ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
-    ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
-    ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s);
-    for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) {
-        printk("  [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n",
-            (ulong) i, (ulong) b->sg_list[i].sg_addr,
-            (ulong) b->sg_list[i].sg_count);
+    printk(" ASC_SG_BLOCK at addr %lx (sgblockno %d)\n",
+        (ulong) b, sgblockno);
+    printk("  sg_cnt %u, sg_ptr %lx\n",
+        b->sg_cnt, (ulong) b->sg_ptr);
+    ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
+    if (b->sg_ptr != NULL)
+    {
+        ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+    }
+    for (i = 0; i < b->sg_cnt; i++) {
+        printk("  [%u]: sg_addr %lx, sg_count %lx\n",
+            i, b->sg_list[i].sg_addr, b->sg_list[i].sg_count);
     }
 }
 
@@ -10116,7 +10825,7 @@
             k = 8;
             m = 0;
         } else {
-            m = (l - i) % 4 ;
+            m = (l - i) % 4;
         }
 
         for (j = 0; j < k; j++) {
@@ -10176,10 +10885,12 @@
  * --- Asc Library Functions
  */
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetEisaChipCfg(
                      PortAddr iop_base
 )
+)
 {
     PortAddr            eisa_cfg_iop;
 
@@ -10188,11 +10899,13 @@
     return (inpw(eisa_cfg_iop));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscSetChipScsiID(
                     PortAddr iop_base,
                     uchar new_host_id
 )
+)
 {
     ushort              cfg_lsw;
 
@@ -10206,10 +10919,12 @@
     return (AscGetChipScsiID(iop_base));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetChipScsiCtrl(
                       PortAddr iop_base
 )
+)
 {
     uchar               sc;
 
@@ -10219,11 +10934,13 @@
     return (sc);
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetChipVersion(
                      PortAddr iop_base,
                      ushort bus_type
 )
+)
 {
     if ((bus_type & ASC_IS_EISA) != 0) {
         PortAddr            eisa_iop;
@@ -10236,10 +10953,12 @@
     return (AscGetChipVerNo(iop_base));
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetChipBusType(
                      PortAddr iop_base
 )
+)
 {
     ushort              chip_ver;
 
@@ -10269,13 +10988,15 @@
     return (0);
 }
 
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
 AscLoadMicroCode(
                     PortAddr iop_base,
                     ushort s_addr,
                     ushort *mcode_buf,
                     ushort mcode_size
 )
+)
 {
     ulong               chksum;
     ushort              mcode_word_size;
@@ -10293,10 +11014,12 @@
     return (chksum);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscFindSignature(
                     PortAddr iop_base
 )
+)
 {
     ushort              sig_word;
 
@@ -10317,11 +11040,13 @@
     ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
 };
 
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
 AscSearchIOPortAddr(
                        PortAddr iop_beg,
                        ushort bus_type
 )
+)
 {
     if (bus_type & ASC_IS_VL) {
         while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
@@ -10352,10 +11077,12 @@
     return (0);
 }
 
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
 AscSearchIOPortAddr11(
                          PortAddr s_addr
 )
+)
 {
     int                 i;
     PortAddr            iop_base;
@@ -10381,30 +11108,36 @@
     return (0);
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscToggleIRQAct(
                    PortAddr iop_base
 )
+)
 {
     AscSetChipStatus(iop_base, CIW_IRQ_ACT);
     AscSetChipStatus(iop_base, 0);
     return;
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscSetISAPNPWaitForKey(
     void)
+)
 {
     outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
     outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
     return;
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetChipIRQ(
                  PortAddr iop_base,
                  ushort bus_type
 )
+)
 {
     ushort              cfg_lsw;
     uchar               chip_irq;
@@ -10434,12 +11167,14 @@
     return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscSetChipIRQ(
                  PortAddr iop_base,
                  uchar irq_no,
                  ushort bus_type
 )
+)
 {
     ushort              cfg_lsw;
 
@@ -10473,10 +11208,12 @@
     return (0);
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscEnableIsaDma(
                    uchar dma_channel
 )
+)
 {
     if (dma_channel < 4) {
         outp(0x000B, (ushort) (0xC0 | dma_channel));
@@ -10527,7 +11264,6 @@
     tid_no = ASC_TIX_TO_TID(target_ix);
     target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
     if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-
         asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
     } else {
         asyn_sdtr = 0;
@@ -10754,19 +11490,169 @@
                      */
                     boardp->queue_full |= target_id;
                     boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
-#if ASC_QUEUE_FLOW_CONTROL
-                    if (boardp->device[tid_no] != NULL &&
-                        boardp->device[tid_no]->queue_curr_depth >
-                        cur_dvc_qng) {
-                        boardp->device[tid_no]->queue_curr_depth =
-                            cur_dvc_qng;
-                    }
-#endif /* ASC_QUEUE_FLOW_CONTROL */
                 }
             }
         }
         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
         return (0);
+    } else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
+    {
+         uchar              q_no;
+         ushort             q_addr;
+         ulong              srb_ptr;
+         uchar              sg_wk_q_no;
+         uchar              first_sg_wk_q_no;
+         ASC_SCSI_Q         *scsiq; /* Ptr to driver request. */
+         ASC_SG_HEAD        *sg_head; /* Ptr to driver SG request. */
+         ASC_SG_LIST_Q      scsi_sg_q; /* Structure written to queue. */
+         ushort             sg_list_dwords;
+         ushort             sg_entry_cnt;
+         uchar              next_qp;
+         int                i;
+
+         q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
+         if (q_no == ASC_QLINK_END)
+         {
+             return(0);
+         }
+
+         q_addr = ASC_QNO_TO_QADDR(q_no);
+
+         /* Read request's SRB pointer. */
+         srb_ptr = AscReadLramDWord(iop_base,
+                           (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR));
+
+         /*
+          * Get request's first and working SG queue.
+          */
+         sg_wk_q_no = AscReadLramByte(iop_base,
+             (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
+
+         first_sg_wk_q_no = AscReadLramByte(iop_base,
+             (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
+
+         /*
+          * Reset request's working SG queue back to the
+          * first SG queue.
+          */
+         AscWriteLramByte(iop_base,
+             (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
+             first_sg_wk_q_no);
+
+         /*
+          * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+          * structure pointer using a macro provided by the driver.
+          * The ASC_SCSI_REQ pointer provides a pointer to the
+          * host ASC_SG_HEAD structure.
+          */
+         scsiq = (ASC_SCSI_Q *) ASC_SRB2SCSIQ(srb_ptr);
+
+         sg_head = scsiq->sg_head;
+
+         /*
+          * Set sg_entry_cnt to the number of SG elements
+          * that will be completed on this interrupt.
+          *
+          * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+          * SG elements. The data_cnt and data_addr fields which
+          * add 1 to the SG element capacity are not used when
+          * restarting SG handling after a halt.
+          */
+         if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
+         {
+              sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+              /*
+               * Keep track of remaining number of SG elements that will
+               * need to be handled on the next interrupt.
+               */
+              scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+         } else
+         {
+              sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+              scsiq->remain_sg_entry_cnt = 0;
+         }
+
+         /*
+          * Copy SG elements into the list of allocated SG queues.
+          *
+          * Last index completed is saved in scsiq->next_sg_index.
+          */
+         next_qp = first_sg_wk_q_no;
+         q_addr = ASC_QNO_TO_QADDR(next_qp);
+         scsi_sg_q.sg_head_qp = q_no;
+         scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+         for( i = 0; i < sg_head->queue_cnt; i++)
+         {
+              scsi_sg_q.seq_no = i + 1;
+              if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
+              {
+                  sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+                  sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                  /*
+                   * After very first SG queue RISC FW uses next
+                   * SG queue first element then checks sg_list_cnt
+                   * against zero and then decrements, so set
+                   * sg_list_cnt 1 less than number of SG elements
+                   * in each SG queue.
+                   */
+                  scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                  scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+              } else {
+                  /*
+                   * This is the last SG queue in the list of
+                   * allocated SG queues. If there are more
+                   * SG elements than will fit in the allocated
+                   * queues, then set the QCSG_SG_XFER_MORE flag.
+                   */
+                  if (scsiq->remain_sg_entry_cnt != 0)
+                  {
+                      scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                  } else
+                  {
+                      scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                  }
+                  /* equals sg_entry_cnt * 2 */
+                  sg_list_dwords = sg_entry_cnt << 1;
+                  scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                  scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                  sg_entry_cnt = 0;
+              }
+
+              scsi_sg_q.q_no = next_qp;
+              AscMemWordCopyToLram(iop_base,
+                           (ushort) (q_addr+ASC_SCSIQ_SGHD_CPY_BEG),
+                           (ushort *) &scsi_sg_q,
+                           (ushort) (sizeof(ASC_SG_LIST_Q) >> 1));
+
+              AscMemDWordCopyToLram( iop_base,
+                           (ushort) (q_addr+ASC_SGQ_LIST_BEG ),
+                           (ulong *) &sg_head->sg_list[scsiq->next_sg_index],
+                           (ushort) sg_list_dwords);
+
+              scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+              /*
+               * If the just completed SG queue contained the
+               * last SG element, then no more SG queues need
+               * to be written.
+               */
+              if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
+              {
+                  break;
+              }
+
+              next_qp = AscReadLramByte( iop_base,
+                           ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
+              q_addr = ASC_QNO_TO_QADDR( next_qp );
+         }
+
+         /*
+          * Clear the halt condition so the RISC will be restarted
+          * after the return.
+          */
+         AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+         return(0);
     }
     return (0);
 }
@@ -10798,8 +11684,18 @@
                         (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
     scsiq->sense_len = (uchar) _val;
     scsiq->extra_bytes = (uchar) (_val >> 8);
-    scsiq->remain_bytes = AscReadLramWord(iop_base,
-                 (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
+    /*
+     * Read high word of remain bytes from alternate location.
+     */
+    scsiq->remain_bytes = (((ulong) AscReadLramWord( iop_base,
+                      (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
+    /*
+     * Read low word of remain bytes from original location.
+     */
+    scsiq->remain_bytes += AscReadLramWord(iop_base,
+        (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
     scsiq->remain_bytes &= max_dma_count;
     return (sg_queue_cnt);
 }
@@ -10957,6 +11853,12 @@
 
     iop_base = asc_dvc->iop_base;
     int_pending = FALSE;
+
+    if (AscIsIntPending(iop_base) == 0)
+    {
+        return int_pending;
+    }
+
     if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
         || (asc_dvc->isr_callback == 0)
 ) {
@@ -10977,10 +11879,15 @@
     chipstat = AscGetChipStatus(iop_base);
     if (chipstat & CSW_SCSI_RESET_LATCH) {
         if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+            int i = 10;
             int_pending = TRUE;
             asc_dvc->sdtr_done = 0;
             saved_ctrl_reg &= (uchar) (~CC_HALT);
-            while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+            while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) &&
+                   (i-- > 0))
+            {
+                  DvcSleepMilliSecond(100);
+            }
             AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
             AscSetChipControl(iop_base, CC_HALT);
             AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
@@ -11034,82 +11941,82 @@
   0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x91,  0x10,  0x0A,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xC3,  0x12,  0x0D,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
   0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x23,  0x00,  0x24,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
-  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xE2,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x00,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xE4,  0x88,  0x00,  0x00,  0x00,  0x00,
   0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
   0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
   0x1E,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
   0x4F,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
-  0x92,  0x80,  0x00,  0x46,  0x17,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
+  0x92,  0x80,  0x00,  0x46,  0x15,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
   0x00,  0xA3,  0xD6,  0x00,  0xA6,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xE6,  0x84,  0xD2,  0xC1,
-  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xE2,  0x01,  0xA6,  0x97,  0xCE,  0x81,  0x00,  0x33,
-  0x02,  0x00,  0xC0,  0x88,  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0x02,  0x01,  0x4F,  0x00,
-  0x84,  0x97,  0x07,  0xA6,  0x0C,  0x01,  0x00,  0x33,  0x03,  0x00,  0xC0,  0x88,  0x03,  0x03,  0x03,  0xDE,
-  0x00,  0x33,  0x05,  0x00,  0xC0,  0x88,  0xCE,  0x00,  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,
-  0x00,  0xA2,  0x80,  0x01,  0x80,  0x63,  0x07,  0xA6,  0x2C,  0x01,  0x80,  0x81,  0x03,  0x03,  0x80,  0x63,
-  0xE2,  0x00,  0x07,  0xA6,  0x3C,  0x01,  0x00,  0x33,  0x04,  0x00,  0xC0,  0x88,  0x03,  0x07,  0x02,  0x01,
-  0x04,  0xCA,  0x0D,  0x23,  0x68,  0x98,  0x4D,  0x04,  0x04,  0x85,  0x05,  0xD8,  0x0D,  0x23,  0x68,  0x98,
-  0xCD,  0x04,  0x15,  0x23,  0xF6,  0x88,  0xFB,  0x23,  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,
-  0x06,  0xA3,  0x6A,  0x01,  0x00,  0x33,  0x0A,  0x00,  0xC0,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x76,  0x01,
-  0x00,  0x33,  0x0B,  0x00,  0xC0,  0x88,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xC0,  0x88,
-  0x50,  0x04,  0x90,  0x81,  0x06,  0xAB,  0x8A,  0x01,  0x90,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x9A,  0x01,
-  0x50,  0x00,  0x00,  0xA3,  0x44,  0x01,  0x00,  0x05,  0x84,  0x81,  0x46,  0x97,  0x02,  0x01,  0x05,  0xC6,
-  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,  0xC6,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,
-  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xBC,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,
-  0x00,  0x33,  0x1B,  0x00,  0xC0,  0x88,  0x06,  0x23,  0x68,  0x98,  0xCD,  0x04,  0xE6,  0x84,  0x06,  0x01,
-  0x00,  0xA2,  0xDC,  0x01,  0x57,  0x60,  0x00,  0xA0,  0xE2,  0x01,  0xE6,  0x84,  0x80,  0x23,  0xA0,  0x01,
-  0xE6,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x08,  0x02,  0x04,  0x01,  0x0C,  0xDE,
-  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x84,  0x97,  0x04,  0x82,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,
-  0x4F,  0x00,  0x62,  0x97,  0x48,  0x04,  0x84,  0x80,  0xF0,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,
-  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x67,  0xEB,
-  0x11,  0x23,  0xF6,  0x88,  0x04,  0x98,  0xF4,  0x80,  0x80,  0x73,  0x80,  0x77,  0x07,  0xA4,  0x32,  0x02,
-  0x7C,  0x95,  0x06,  0xA6,  0x3C,  0x02,  0x03,  0xA6,  0x4C,  0x04,  0xC0,  0x88,  0x04,  0x01,  0x03,  0xD8,
-  0xB2,  0x98,  0x6A,  0x96,  0x4E,  0x82,  0xFE,  0x95,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,
-  0x02,  0xA6,  0x78,  0x02,  0x07,  0xA6,  0x66,  0x02,  0x06,  0xA6,  0x6A,  0x02,  0x03,  0xA6,  0x6E,  0x02,
-  0x00,  0x33,  0x10,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0x50,  0x82,  0x60,  0x96,  0x50,  0x82,  0x04,  0x23,
-  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,  0x3C,  0x84,  0x04,  0x01,  0x0C,  0xDC,  0xE0,  0x23,  0x25,  0x61,
-  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,  0x03,  0x23,  0xA4,  0x01,
-  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,  0x1C,  0x01,  0x02,  0xA6,  0xB6,  0x02,  0x07,  0xA6,  0x66,  0x02,
-  0x06,  0xA6,  0x6A,  0x02,  0x03,  0xA6,  0x20,  0x04,  0x01,  0xA6,  0xC0,  0x02,  0x00,  0xA6,  0xC0,  0x02,
-  0x00,  0x33,  0x12,  0x00,  0xC0,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,  0x00,  0xA0,  0x98,  0x02,
-  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,  0x10,  0x31,  0x12,  0x35,
-  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xF6,  0x82,  0x18,  0x23,  0x04,  0x61,
-  0x18,  0xA0,  0xEE,  0x02,  0x04,  0x01,  0x9C,  0xC8,  0x00,  0x33,  0x1F,  0x00,  0xC0,  0x88,  0x08,  0x31,
-  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,  0x7E,  0x98,  0xB6,  0x2D,  0x01,  0xA6,  0x20,  0x03,  0x00,  0xA6,
-  0x20,  0x03,  0x07,  0xA6,  0x18,  0x03,  0x06,  0xA6,  0x1C,  0x03,  0x03,  0xA6,  0x20,  0x04,  0x02,  0xA6,
-  0x78,  0x02,  0x00,  0x33,  0x33,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0xFA,  0x82,  0x60,  0x96,  0xFA,  0x82,
-  0x82,  0x98,  0x80,  0x42,  0x7E,  0x98,  0x60,  0xE4,  0x04,  0x01,  0x29,  0xC8,  0x31,  0x05,  0x07,  0x01,
-  0x00,  0xA2,  0x60,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x86,  0x98,  0x7E,  0x98,  0x00,  0xA6,
-  0x22,  0x03,  0x07,  0xA6,  0x58,  0x03,  0x03,  0xA6,  0x3C,  0x04,  0x06,  0xA6,  0x5C,  0x03,  0x01,  0xA6,
-  0x22,  0x03,  0x00,  0x33,  0x25,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0x3E,  0x83,  0x60,  0x96,  0x3E,  0x83,
-  0x04,  0x01,  0x0C,  0xCE,  0x03,  0xC8,  0x00,  0x33,  0x42,  0x00,  0xC0,  0x88,  0x00,  0x01,  0x05,  0x05,
-  0xFF,  0xA2,  0x7E,  0x03,  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x3A,  0x83,  0x05,  0x05,  0x15,  0x01,
-  0x00,  0xA2,  0x9E,  0x03,  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,
-  0x01,  0xA6,  0x9A,  0x03,  0x00,  0xA6,  0x9A,  0x03,  0x12,  0x84,  0x80,  0x42,  0x7E,  0x98,  0x01,  0xA6,
-  0xA8,  0x03,  0x00,  0xA6,  0xC0,  0x03,  0x12,  0x84,  0xA6,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA8,  0x03,
-  0x07,  0xA6,  0xB6,  0x03,  0xD8,  0x83,  0x7C,  0x95,  0xAC,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xC0,  0x88,
-  0xA6,  0x98,  0x80,  0x42,  0x00,  0xA6,  0xC0,  0x03,  0x07,  0xA6,  0xCE,  0x03,  0xD8,  0x83,  0x7C,  0x95,
-  0xC4,  0x83,  0x00,  0x33,  0x26,  0x00,  0xC0,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,
-  0xA0,  0x01,  0x12,  0x23,  0xA1,  0x01,  0x12,  0x84,  0x06,  0xF0,  0x06,  0xA4,  0xF6,  0x03,  0x80,  0x6B,
-  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,  0x03,  0xA6,  0x10,  0x04,  0x07,  0xA6,  0x08,  0x04,  0x06,  0xA6,
-  0x0C,  0x04,  0x00,  0x33,  0x17,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0xF6,  0x83,  0x60,  0x96,  0xF6,  0x83,
-  0x20,  0x84,  0x06,  0xF0,  0x06,  0xA4,  0x20,  0x04,  0x80,  0x6B,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xDA,  0x01,  0xA6,  0x97,  0xC6,  0x81,  0xC2,  0x88,
+  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0xFE,  0x00,  0x4F,  0x00,  0x84,  0x97,  0x07,  0xA6,
+  0x08,  0x01,  0x00,  0x33,  0x03,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x01,  0xDE,  0xC2,  0x88,  0xCE,  0x00,
+  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,  0x00,  0xA2,  0x78,  0x01,  0x80,  0x63,  0x07,  0xA6,
+  0x24,  0x01,  0x78,  0x81,  0x03,  0x03,  0x80,  0x63,  0xE2,  0x00,  0x07,  0xA6,  0x34,  0x01,  0x00,  0x33,
+  0x04,  0x00,  0xC2,  0x88,  0x03,  0x07,  0x02,  0x01,  0x04,  0xCA,  0x0D,  0x23,  0x68,  0x98,  0x4D,  0x04,
+  0x04,  0x85,  0x05,  0xD8,  0x0D,  0x23,  0x68,  0x98,  0xCD,  0x04,  0x15,  0x23,  0xF8,  0x88,  0xFB,  0x23,
+  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,  0x06,  0xA3,  0x62,  0x01,  0x00,  0x33,  0x0A,  0x00,
+  0xC2,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x6E,  0x01,  0x00,  0x33,  0x0B,  0x00,  0xC2,  0x88,  0xCD,  0x04,
+  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xC2,  0x88,  0x50,  0x04,  0x88,  0x81,  0x06,  0xAB,  0x82,  0x01,
+  0x88,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x92,  0x01,  0x50,  0x00,  0x00,  0xA3,  0x3C,  0x01,  0x00,  0x05,
+  0x7C,  0x81,  0x46,  0x97,  0x02,  0x01,  0x05,  0xC6,  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,
+  0xBE,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,
+  0xB4,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1B,  0x00,  0xC2,  0x88,  0x06,  0x23,
+  0x68,  0x98,  0xCD,  0x04,  0xE6,  0x84,  0x06,  0x01,  0x00,  0xA2,  0xD4,  0x01,  0x57,  0x60,  0x00,  0xA0,
+  0xDA,  0x01,  0xE6,  0x84,  0x80,  0x23,  0xA0,  0x01,  0xE6,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,
+  0x00,  0xA2,  0x00,  0x02,  0x04,  0x01,  0x0C,  0xDE,  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x84,  0x97,
+  0xFC,  0x81,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,  0x4F,  0x00,  0x62,  0x97,  0x48,  0x04,  0x84,  0x80,
+  0xF0,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,
+  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x6B,  0xEB,  0x11,  0x23,  0xF8,  0x88,  0x04,  0x98,  0xF0,  0x80,
+  0x80,  0x73,  0x80,  0x77,  0x07,  0xA4,  0x2A,  0x02,  0x7C,  0x95,  0x06,  0xA6,  0x34,  0x02,  0x03,  0xA6,
+  0x4C,  0x04,  0x46,  0x82,  0x04,  0x01,  0x03,  0xD8,  0xB4,  0x98,  0x6A,  0x96,  0x46,  0x82,  0xFE,  0x95,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x6C,  0x02,  0x07,  0xA6,  0x5A,  0x02,
+  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x62,  0x02,  0xC2,  0x88,  0x7C,  0x95,  0x48,  0x82,  0x60,  0x96,
+  0x48,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,  0x3C,  0x84,  0x04,  0x01,  0x0C,  0xDC,
+  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,
+  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,  0x1C,  0x01,  0x02,  0xA6,  0xAA,  0x02,
+  0x07,  0xA6,  0x5A,  0x02,  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x20,  0x04,  0x01,  0xA6,  0xB4,  0x02,
+  0x00,  0xA6,  0xB4,  0x02,  0x00,  0x33,  0x12,  0x00,  0xC2,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,
+  0x00,  0xA0,  0x8C,  0x02,  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,
+  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xEA,  0x82,
+  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,  0xE2,  0x02,  0x04,  0x01,  0xA2,  0xC8,  0x00,  0x33,  0x1F,  0x00,
+  0xC2,  0x88,  0x08,  0x31,  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,  0x7E,  0x98,  0xB6,  0x2D,  0x01,  0xA6,
+  0x14,  0x03,  0x00,  0xA6,  0x14,  0x03,  0x07,  0xA6,  0x0C,  0x03,  0x06,  0xA6,  0x10,  0x03,  0x03,  0xA6,
+  0x20,  0x04,  0x02,  0xA6,  0x6C,  0x02,  0x00,  0x33,  0x33,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xEE,  0x82,
+  0x60,  0x96,  0xEE,  0x82,  0x82,  0x98,  0x80,  0x42,  0x7E,  0x98,  0x64,  0xE4,  0x04,  0x01,  0x2D,  0xC8,
+  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,  0x54,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x86,  0x98,
+  0x7E,  0x98,  0x00,  0xA6,  0x16,  0x03,  0x07,  0xA6,  0x4C,  0x03,  0x03,  0xA6,  0x3C,  0x04,  0x06,  0xA6,
+  0x50,  0x03,  0x01,  0xA6,  0x16,  0x03,  0x00,  0x33,  0x25,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x32,  0x83,
+  0x60,  0x96,  0x32,  0x83,  0x04,  0x01,  0x10,  0xCE,  0x07,  0xC8,  0x05,  0x05,  0xEB,  0x04,  0x00,  0x33,
+  0x00,  0x20,  0xC0,  0x20,  0x81,  0x62,  0x72,  0x83,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,  0x7A,  0x03,
+  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x2E,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,  0x9A,  0x03,
+  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,  0x96,  0x03,
+  0x00,  0xA6,  0x96,  0x03,  0x10,  0x84,  0x80,  0x42,  0x7E,  0x98,  0x01,  0xA6,  0xA4,  0x03,  0x00,  0xA6,
+  0xBC,  0x03,  0x10,  0x84,  0xA8,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA4,  0x03,  0x07,  0xA6,  0xB2,  0x03,
+  0xD4,  0x83,  0x7C,  0x95,  0xA8,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xC2,  0x88,  0xA8,  0x98,  0x80,  0x42,
+  0x00,  0xA6,  0xBC,  0x03,  0x07,  0xA6,  0xCA,  0x03,  0xD4,  0x83,  0x7C,  0x95,  0xC0,  0x83,  0x00,  0x33,
+  0x26,  0x00,  0xC2,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,  0x12,  0x23,
+  0xA1,  0x01,  0x10,  0x84,  0x07,  0xF0,  0x06,  0xA4,  0xF4,  0x03,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,
+  0x83,  0x03,  0x80,  0x63,  0x03,  0xA6,  0x0E,  0x04,  0x07,  0xA6,  0x06,  0x04,  0x06,  0xA6,  0x0A,  0x04,
+  0x00,  0x33,  0x17,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xF4,  0x83,  0x60,  0x96,  0xF4,  0x83,  0x20,  0x84,
+  0x07,  0xF0,  0x06,  0xA4,  0x20,  0x04,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
   0xB6,  0x2D,  0x03,  0xA6,  0x3C,  0x04,  0x07,  0xA6,  0x34,  0x04,  0x06,  0xA6,  0x38,  0x04,  0x00,  0x33,
-  0x30,  0x00,  0xC0,  0x88,  0x7C,  0x95,  0x20,  0x84,  0x60,  0x96,  0x20,  0x84,  0x1D,  0x01,  0x06,  0xCC,
+  0x30,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x20,  0x84,  0x60,  0x96,  0x20,  0x84,  0x1D,  0x01,  0x06,  0xCC,
   0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,
-  0x07,  0xA6,  0x5A,  0x04,  0x00,  0x33,  0x18,  0x00,  0xC0,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,
+  0x07,  0xA6,  0x5A,  0x04,  0x00,  0x33,  0x18,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,
   0x07,  0xA4,  0x64,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x86,  0x04,  0x0A,  0xA0,  0x76,  0x04,  0xE0,  0x00,
-  0x00,  0x33,  0x1D,  0x00,  0xC0,  0x88,  0x0B,  0xA0,  0x82,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,
-  0xC0,  0x88,  0x42,  0x23,  0xF6,  0x88,  0x00,  0x23,  0x22,  0xA3,  0xE6,  0x04,  0x08,  0x23,  0x22,  0xA3,
+  0x00,  0x33,  0x1D,  0x00,  0xC2,  0x88,  0x0B,  0xA0,  0x82,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,
+  0xC2,  0x88,  0x42,  0x23,  0xF8,  0x88,  0x00,  0x23,  0x22,  0xA3,  0xE6,  0x04,  0x08,  0x23,  0x22,  0xA3,
   0xA2,  0x04,  0x28,  0x23,  0x22,  0xA3,  0xAE,  0x04,  0x02,  0x23,  0x22,  0xA3,  0xC4,  0x04,  0x42,  0x23,
-  0xF6,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xAE,  0x04,  0x45,  0x23,  0xF6,  0x88,  0x04,  0x98,
-  0x00,  0xA2,  0xC0,  0x04,  0xB2,  0x98,  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xF0,  0x81,
-  0x47,  0x23,  0xF6,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0x04,  0x98,  0xB2,  0x98,  0x00,  0x33,  0x00,  0x81,
-  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x08,  0x02,  0x43,  0x23,  0xF6,  0x88,  0x04,  0x23,
+  0xF8,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xAE,  0x04,  0x45,  0x23,  0xF8,  0x88,  0x04,  0x98,
+  0x00,  0xA2,  0xC0,  0x04,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xE8,  0x81,
+  0x47,  0x23,  0xF8,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0x04,  0x98,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x81,
+  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x00,  0x02,  0x43,  0x23,  0xF8,  0x88,  0x04,  0x23,
   0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,  0x03,  0xA3,  0xF4,  0x04,  0x00,  0x33,
-  0x27,  0x00,  0xC0,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,
+  0x27,  0x00,  0xC2,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,
   0x04,  0x98,  0x26,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,  0x4F,  0x00,  0x00,  0xA3,  0x22,  0x05,
   0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1C,  0x05,  0x0A,  0x85,  0x46,  0x97,  0xCD,  0x04,
   0x24,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,  0x80,  0x23,  0x82,  0x01,  0x34,  0x85,
@@ -11118,16 +12025,16 @@
   0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,
   0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x60,  0x05,  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,
   0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,  0x00,  0x63,  0x07,  0xA4,  0xF8,  0x05,
-  0x03,  0x03,  0x02,  0xA0,  0x8E,  0x05,  0xF4,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xC0,  0x88,  0x04,  0xA0,
+  0x03,  0x03,  0x02,  0xA0,  0x8E,  0x05,  0xF4,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xC2,  0x88,  0x04,  0xA0,
   0xB8,  0x05,  0x80,  0x63,  0x00,  0x23,  0xDF,  0x00,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0xA4,  0x05,
   0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x62,  0x97,  0x04,  0x85,
   0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0x04,  0x85,  0x08,  0xA0,  0xBE,  0x05,  0xF4,  0x85,  0x03,  0xA0,
   0xC4,  0x05,  0xF4,  0x85,  0x01,  0xA0,  0xCE,  0x05,  0x88,  0x00,  0x80,  0x63,  0xCC,  0x86,  0x07,  0xA0,
   0xEE,  0x05,  0x5F,  0x00,  0x00,  0x2B,  0xDF,  0x08,  0x00,  0xA2,  0xE6,  0x05,  0x80,  0x67,  0x80,  0x63,
-  0x01,  0xA2,  0x7A,  0x06,  0x7C,  0x85,  0x06,  0x23,  0x68,  0x98,  0x48,  0x23,  0xF6,  0x88,  0x07,  0x23,
+  0x01,  0xA2,  0x7A,  0x06,  0x7C,  0x85,  0x06,  0x23,  0x68,  0x98,  0x48,  0x23,  0xF8,  0x88,  0x07,  0x23,
   0x80,  0x00,  0x06,  0x87,  0x80,  0x63,  0x7C,  0x85,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x4A,  0x00,
   0x06,  0x61,  0x00,  0xA2,  0x36,  0x06,  0x1D,  0x01,  0x16,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,
-  0x80,  0x63,  0x06,  0xA6,  0x1C,  0x06,  0x00,  0x33,  0x37,  0x00,  0xC0,  0x88,  0x1D,  0x01,  0x01,  0xD6,
+  0x80,  0x63,  0x06,  0xA6,  0x1C,  0x06,  0x00,  0x33,  0x37,  0x00,  0xC2,  0x88,  0x1D,  0x01,  0x01,  0xD6,
   0x20,  0x23,  0x63,  0x60,  0x83,  0x03,  0x80,  0x63,  0x02,  0x23,  0xDF,  0x00,  0x07,  0xA6,  0x7C,  0x05,
   0xEF,  0x04,  0x6F,  0x00,  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,
   0x00,  0xA2,  0x4E,  0x06,  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,
@@ -11139,12 +12046,12 @@
   0x01,  0x00,  0x06,  0xA6,  0xAA,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,
   0x00,  0xA0,  0xA2,  0x06,  0x06,  0xA6,  0xBC,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x80,  0x67,  0x40,  0x0E,
   0x80,  0x63,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x07,  0xA6,  0xD6,  0x06,
-  0x00,  0x33,  0x2A,  0x00,  0xC0,  0x88,  0x03,  0x03,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,
-  0xE8,  0x06,  0x00,  0x33,  0x29,  0x00,  0xC0,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xF4,  0x06,  0xC0,  0x0E,
+  0x00,  0x33,  0x2A,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,
+  0xE8,  0x06,  0x00,  0x33,  0x29,  0x00,  0xC2,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xF4,  0x06,  0xC0,  0x0E,
   0x80,  0x63,  0xDE,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,
   0x02,  0xDA,  0x80,  0x63,  0x7C,  0x85,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x8C,  0x06,  0x00,  0x33,
-  0x2C,  0x00,  0xC0,  0x88,  0x0C,  0xA2,  0x2E,  0x07,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,
-  0x2C,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xC0,  0x88,  0x00,  0x00,  0x80,  0x67,
+  0x2C,  0x00,  0xC2,  0x88,  0x0C,  0xA2,  0x2E,  0x07,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,
+  0x2C,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xC2,  0x88,  0x00,  0x00,  0x80,  0x67,
   0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,  0x44,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0xBF,  0x23,  0x04,  0x61,
   0x84,  0x01,  0xE6,  0x84,  0x00,  0x63,  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,
   0x01,  0x05,  0x80,  0x01,  0x72,  0x04,  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,
@@ -11154,7 +12061,7 @@
   0x80,  0x01,  0x70,  0x04,  0x71,  0x00,  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,
   0x81,  0x01,  0x70,  0x04,  0x00,  0x63,  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,
   0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xC4,  0x07,  0x00,  0x33,
-  0x07,  0x00,  0xC0,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,
+  0x07,  0x00,  0xC2,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,
   0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xE4,  0x07,
   0x00,  0x05,  0xDA,  0x87,  0x00,  0x01,  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,
   0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,
@@ -11165,19 +12072,19 @@
   0x26,  0x95,  0x24,  0x88,  0x73,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x5A,  0x88,  0x02,  0x01,
   0x04,  0xD8,  0x46,  0x97,  0x04,  0x98,  0x26,  0x95,  0x4A,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x64,  0x08,
   0x00,  0x05,  0x4E,  0x88,  0x73,  0x04,  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x76,  0x08,
-  0x00,  0x33,  0x3E,  0x00,  0xC0,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,
+  0x00,  0x33,  0x3E,  0x00,  0xC2,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,
   0x9C,  0x88,  0x38,  0x2B,  0x92,  0x88,  0x32,  0x09,  0x31,  0x05,  0x92,  0x98,  0x05,  0x05,  0xB2,  0x09,
   0x00,  0x63,  0x00,  0x32,  0x00,  0x36,  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,
-  0x80,  0x3A,  0x80,  0x3E,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,  0x40,  0x3E,
-  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xB2,  0x08,  0x5D,  0x00,  0xFE,  0xC3,  0x00,  0x63,
-  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,  0x13,  0x23,
-  0xF6,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,  0x81,  0x62,
-  0xE0,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,  0xF1,  0xC7,
-  0x41,  0x23,  0xF6,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
+  0x80,  0x3A,  0x80,  0x3E,  0xB4,  0x3D,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,
+  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xB4,  0x08,  0x5D,  0x00,  0xFE,  0xC3,
+  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,
+  0x13,  0x23,  0xF8,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,
+  0x81,  0x62,  0xE2,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,
+  0xF1,  0xC7,  0x41,  0x23,  0xF8,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
 };
 
 STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
-STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012B5442UL;
+STATIC ulong  _asc_mcode_chksum ASC_INITDATA = 0x012C453FUL;
 
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
 STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
@@ -11244,7 +12151,7 @@
     n_q_required = 1;
     if (scsiq->cdbptr[0] == SCSICMD_RequestSense) {
         if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
-            asc_dvc->sdtr_done &= ~scsiq->q1.target_id ;
+            asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
             sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
             AscMsgOutSDTR(asc_dvc,
                           asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
@@ -11266,12 +12173,15 @@
             DvcLeaveCritical(last_int_level);
             return (ERR);
         }
-        if (sg_entry_cnt > ASC_MAX_SG_LIST) {
-            return (ERR);
+#if !CC_VERY_LONG_SG_LIST
+        if (sg_entry_cnt > ASC_MAX_SG_LIST)
+        {
+            return(ERR);
         }
+#endif /* !CC_VERY_LONG_SG_LIST */
         if (sg_entry_cnt == 1) {
-            scsiq->q1.data_addr = sg_head->sg_list[0].addr;
-            scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
+            scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
+            scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
             scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
         }
         sg_entry_cnt_minus_one = sg_entry_cnt - 1;
@@ -11283,7 +12193,7 @@
         if (scsiq->q1.cntl & QC_SG_HEAD) {
             data_cnt = 0;
             for (i = 0; i < sg_entry_cnt; i++) {
-                data_cnt += sg_head->sg_list[i].bytes;
+                data_cnt += (ulong) sg_head->sg_list[i].bytes;
             }
         } else {
             data_cnt = scsiq->q1.data_cnt;
@@ -11317,8 +12227,9 @@
             if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
                 if ((scsi_cmd == SCSICMD_Read6) ||
                     (scsi_cmd == SCSICMD_Read10)) {
-                    addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr +
-                      sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
+                    addr =
+                        (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].addr +
+                        (ulong) sg_head->sg_list[sg_entry_cnt_minus_one].bytes;
                     extra_bytes = (uchar) ((ushort) addr & 0x0003);
                     if ((extra_bytes != 0) &&
                         ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
@@ -11332,6 +12243,15 @@
             }
         }
         sg_head->entry_to_copy = sg_head->entry_cnt;
+        /*
+         * Set the sg_entry_cnt to the maximum possible. The rest of
+         * the SG elements will be copied when the RISC completes the
+         * SG elements that fit and halts.
+         */
+        if (sg_entry_cnt > ASC_MAX_SG_LIST)
+        {
+             sg_entry_cnt = ASC_MAX_SG_LIST;
+        }
         n_q_required = AscSgListToQueue(sg_entry_cnt);
         if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
             (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
@@ -11558,9 +12478,39 @@
     sg_head = scsiq->sg_head;
     saved_data_addr = scsiq->q1.data_addr;
     saved_data_cnt = scsiq->q1.data_cnt;
-    scsiq->q1.data_addr = sg_head->sg_list[0].addr;
-    scsiq->q1.data_cnt = sg_head->sg_list[0].bytes;
-    sg_entry_cnt = sg_head->entry_cnt - 1;
+    scsiq->q1.data_addr = (ulong) sg_head->sg_list[0].addr;
+    scsiq->q1.data_cnt = (ulong) sg_head->sg_list[0].bytes;
+    /*
+     * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+     * then not all SG elements will fit in the allocated queues.
+     * The rest of the SG elements will be copied when the RISC
+     * completes the SG elements that fit and halts.
+     */
+    if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+    {
+         /*
+          * Set sg_entry_cnt to be the number of SG elements that
+          * will fit in the allocated SG queues. It is minus 1 because
+          * first SG element handled above. ASC_MAX_SG_LIST is already
+          * inflated by 1 to account for this. For example it may
+          * be 50 which is 1 + 7 queues * 7 SG elements.
+          */
+         sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+         /*
+          * Keep track of remaining number of SG elements that will
+          * need to be handled from a_isr.c.
+          */
+         scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
+    } else
+    {
+         /*
+          * Set sg_entry_cnt to be the number of SG elements that
+          * will fit in the allocated SG queues. Refer to comment
+          * above regarding why it is - 1.
+          */
+         sg_entry_cnt = sg_head->entry_cnt - 1;
+    }
     if (sg_entry_cnt != 0) {
         scsiq->q1.cntl |= QC_SG_HEAD;
         q_addr = ASC_QNO_TO_QADDR(q_no);
@@ -11581,7 +12531,19 @@
                     scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
                 }
             } else {
-                scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                /*
+                 * This is the last SG queue in the list of
+                 * allocated SG queues. If there are more
+                 * SG elements than will fit in the allocated
+                 * queues, then set the QCSG_SG_XFER_MORE flag.
+                 */
+                if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+                {
+                    scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                } else
+                {
+                    scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                }
                 sg_list_dwords = sg_entry_cnt << 1;
                 if (i == 0) {
                     scsi_sg_q.sg_list_cnt = sg_entry_cnt;
@@ -11605,6 +12567,7 @@
                               (ulong *) & sg_head->sg_list[sg_index],
                                   (ushort) sg_list_dwords);
             sg_index += ASC_SG_LIST_PER_Q;
+            scsiq->next_sg_index = sg_index;
         }
     } else {
         scsiq->q1.cntl &= ~QC_SG_HEAD;
@@ -11790,7 +12753,7 @@
         if (org_id == (0x01 << i))
             break;
     }
-    org_id = i;
+    org_id = (ASC_SCSI_BIT_ID_TYPE) i;
     AscWriteChipDvcID(iop_base, id);
     if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
         AscSetBank(iop_base, 0);
@@ -11929,7 +12892,7 @@
     uchar               q_status;
     int                 count = 0;
 
-    while (scsiq->q1.q_no == 0) ;
+    while (scsiq->q1.q_no == 0);
     q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
     do {
         q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS);
@@ -12024,7 +12987,7 @@
 
     period_table = asc_dvc->sdtr_period_tbl;
     max_index = (int) asc_dvc->max_sdtr_index;
-    min_index = (int)asc_dvc->host_init_sdtr_index ;
+    min_index = (int)asc_dvc->host_init_sdtr_index;
     if ((syn_time <= period_table[max_index])) {
         for (i = min_index; i < (max_index - 1); i++) {
             if (syn_time <= period_table[i]) {
@@ -12323,7 +13286,7 @@
     if (sg_head.entry_cnt > 1) {
         return (0L);
     }
-    return (sg_head.sg_list[0].addr);
+    return ((ulong) sg_head.sg_list[0].addr);
 }
 
 STATIC void
@@ -12338,10 +13301,12 @@
     udelay((nano_sec + 999)/1000);
 }
 
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
 AscGetEisaProductID(
                        PortAddr iop_base
 )
+)
 {
     PortAddr            eisa_iop;
     ushort              product_id_high, product_id_low;
@@ -12354,10 +13319,12 @@
     return (product_id);
 }
 
-STATIC PortAddr ASC_INIT
+ASC_INITFUNC(
+STATIC PortAddr,
 AscSearchIOPortAddrEISA(
                            PortAddr iop_base
 )
+)
 {
     ulong               eisa_product_id;
 
@@ -12530,9 +13497,13 @@
 )
 {
     PortAddr    iop_base;
+    int         i = 10;
 
     iop_base = asc_dvc->iop_base;
-    while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
+    while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0))
+    {
+          DvcSleepMilliSecond(100);
+    }
     AscStopChip(iop_base);
     AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
     DvcDelayNanoSecond(asc_dvc, 60000);
@@ -12546,10 +13517,12 @@
     return (AscIsChipHalted(iop_base));
 }
 
-STATIC ulong ASC_INIT
+ASC_INITFUNC(
+STATIC ulong,
 AscGetMaxDmaCount(
                      ushort bus_type
 )
+)
 {
     if (bus_type & ASC_IS_ISA)
         return (ASC_MAX_ISA_DMA_COUNT);
@@ -12558,10 +13531,12 @@
     return (ASC_MAX_PCI_DMA_COUNT);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetIsaDmaChannel(
                        PortAddr iop_base
 )
+)
 {
     ushort              channel;
 
@@ -12573,11 +13548,13 @@
     return (channel + 4);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscSetIsaDmaChannel(
                        PortAddr iop_base,
                        ushort dma_channel
 )
+)
 {
     ushort              cfg_lsw;
     uchar               value;
@@ -12595,11 +13572,13 @@
     return (0);
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscSetIsaDmaSpeed(
                      PortAddr iop_base,
                      uchar speed_value
 )
+)
 {
     speed_value &= 0x07;
     AscSetBank(iop_base, 1);
@@ -12608,10 +13587,12 @@
     return (AscGetIsaDmaSpeed(iop_base));
 }
 
-STATIC uchar ASC_INIT
+ASC_INITFUNC(
+STATIC uchar,
 AscGetIsaDmaSpeed(
                      PortAddr iop_base
 )
+)
 {
     uchar               speed_value;
 
@@ -12622,10 +13603,12 @@
     return (speed_value);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscReadPCIConfigWord(
     ASC_DVC_VAR asc_ptr_type *asc_dvc,
     ushort pci_config_offset)
+)
 {
     uchar       lsb, msb;
 
@@ -12634,10 +13617,12 @@
     return ((ushort) ((msb << 8) | lsb));
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitGetConfig(
         ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ushort              warn_code;
     PortAddr            iop_base;
@@ -12717,10 +13702,12 @@
     return(warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitSetConfig(
                     ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ushort              warn_code = 0;
 
@@ -12736,10 +13723,12 @@
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitFromAscDvcVar(
                         ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     PortAddr            iop_base;
     ushort              cfg_msw;
@@ -12797,16 +13786,15 @@
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitAsc1000Driver(
                         ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ushort              warn_code;
     PortAddr            iop_base;
-    extern ushort       _asc_mcode_size;
-    extern ulong        _asc_mcode_chksum;
-    extern uchar        _asc_mcode_buf[];
 
     iop_base = asc_dvc->iop_base;
     warn_code = 0;
@@ -12837,10 +13825,12 @@
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitAscDvcVar(
                     ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     int                 i;
     PortAddr            iop_base;
@@ -12869,12 +13859,12 @@
     asc_dvc->no_scam = 0;
     asc_dvc->unit_not_ready = 0;
     asc_dvc->queue_full_or_busy = 0;
-    asc_dvc->redo_scam = 0 ;
-    asc_dvc->res2 = 0 ;
-    asc_dvc->host_init_sdtr_index = 0 ;
-    asc_dvc->res7 = 0 ;
-    asc_dvc->res8 = 0 ;
-    asc_dvc->cfg->can_tagged_qng = 0 ;
+    asc_dvc->redo_scam = 0;
+    asc_dvc->res2 = 0;
+    asc_dvc->host_init_sdtr_index = 0;
+    asc_dvc->res7 = 0;
+    asc_dvc->res8 = 0;
+    asc_dvc->cfg->can_tagged_qng = 0;
     asc_dvc->cfg->cmd_qng_enabled = 0;
     asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
     asc_dvc->init_sdtr = 0;
@@ -12950,10 +13940,12 @@
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitFromEEP(
                   ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     ASCEEP_CONFIG       eep_config_buf;
     ASCEEP_CONFIG       *eep_config;
@@ -13031,11 +14023,11 @@
                 /* Indicate EEPROM-less board. */
                 eep_config->adapter_info[5] = 0xBB;
             } else {
-                write_eep = 1 ;
-                warn_code |= ASC_WARN_EEPROM_CHKSUM ;
+                write_eep = 1;
+                warn_code |= ASC_WARN_EEPROM_CHKSUM;
             }
     }
-    asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr ;
+    asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
     asc_dvc->cfg->disc_enable = eep_config->disc_enable;
     asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
     asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed;
@@ -13103,10 +14095,12 @@
     return (warn_code);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscInitMicroCodeVar(
                        ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     int                 i;
     ushort              warn_code;
@@ -13151,10 +14145,12 @@
     return (warn_code);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscTestExternalLram(
                        ASC_DVC_VAR asc_ptr_type * asc_dvc
 )
+)
 {
     PortAddr            iop_base;
     ushort              q_addr;
@@ -13176,11 +14172,13 @@
     return (sta);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscWriteEEPCmdReg(
                      PortAddr iop_base,
                      uchar cmd_reg
 )
+)
 {
     uchar               read_back;
     int                 retry;
@@ -13199,11 +14197,13 @@
     }
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscWriteEEPDataReg(
                       PortAddr iop_base,
                       ushort data_reg
 )
+)
 {
     ushort              read_back;
     int                 retry;
@@ -13222,29 +14222,35 @@
     }
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscWaitEEPRead(
                   void
 )
+)
 {
     DvcSleepMilliSecond(1);
     return;
 }
 
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AscWaitEEPWrite(
                    void
 )
+)
 {
     DvcSleepMilliSecond(20);
     return;
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscReadEEPWord(
                   PortAddr iop_base,
                   uchar addr
 )
+)
 {
     ushort              read_wval;
     uchar               cmd_reg;
@@ -13259,12 +14265,14 @@
     return (read_wval);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscWriteEEPWord(
                    PortAddr iop_base,
                    uchar addr,
                    ushort word_val
 )
+)
 {
     ushort              read_wval;
 
@@ -13284,11 +14292,13 @@
     return (read_wval);
 }
 
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AscGetEEPConfig(
                    PortAddr iop_base,
                    ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
+)
 {
     ushort              wval;
     ushort              sum;
@@ -13323,11 +14333,13 @@
     return (sum);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscSetEEPConfigOnce(
                        PortAddr iop_base,
                        ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
+)
 {
     int                 n_error;
     ushort      *wbuf;
@@ -13378,11 +14390,13 @@
     return (n_error);
 }
 
-STATIC int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AscSetEEPConfig(
                    PortAddr iop_base,
                    ASCEEP_CONFIG * cfg_buf, ushort bus_type
 )
+)
 {
     int            retry;
     int            n_error;
@@ -13406,55 +14420,35 @@
                uchar tid_no,
                ASC_SCSI_INQUIRY *inq)
 {
-    uchar                dvc_type;
-    ASC_SCSI_BIT_ID_TYPE tid_bits;
+    uchar                       dvc_type;
+    ASC_SCSI_BIT_ID_TYPE        tid_bits;
 
     dvc_type = inq->byte0.peri_dvc_type;
     tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
 
-    if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
-        if (!(asc_dvc->init_sdtr & tid_bits)) {
+    if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
+    {
+        if (!(asc_dvc->init_sdtr & tid_bits))
+        {
             if ((dvc_type == SCSI_TYPE_CDROM) &&
                 (AscCompareString((uchar *) inq->vendor_id,
-                    (uchar *) "HP ", 3) == 0)) {
+                    (uchar *) "HP ", 3) == 0))
+            {
                 asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
             }
             asc_dvc->pci_fix_asyn_xfer |= tid_bits;
             if ((dvc_type == SCSI_TYPE_PROC) ||
-                (dvc_type == SCSI_TYPE_SCANNER)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-            if ((dvc_type == SCSI_TYPE_SASD) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "TANDBERG", 8) == 0) &&
-                (AscCompareString((uchar *) inq->product_id,
-                 (uchar *) " TDC 36", 7) == 0)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-            if ((dvc_type == SCSI_TYPE_SASD) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "WANGTEK ", 8) == 0)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-
-            if ((dvc_type == SCSI_TYPE_CDROM) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "NEC     ", 8) == 0) &&
-                (AscCompareString((uchar *) inq->product_id,
-                 (uchar *) "CD-ROM DRIVE    ", 16) == 0)) {
+                (dvc_type == SCSI_TYPE_SCANNER) ||
+                (dvc_type == SCSI_TYPE_CDROM) ||
+                (dvc_type == SCSI_TYPE_SASD))
+            {
                 asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
             }
 
-            if ((dvc_type == SCSI_TYPE_CDROM) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                 (uchar *) "YAMAHA", 6) == 0) &&
-                (AscCompareString((uchar *) inq->product_id,
-                 (uchar *) "CDR400", 6) == 0)) {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
-            if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+            if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+            {
                 AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
-                                        ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+                    ASYN_SDTR_DATA_FIX_PCI_REV_AB);
             }
         }
     }
@@ -13718,299 +14712,666 @@
  * --- Adv Library Functions
  */
 
-/* a_qswap.h */
-STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = {
-  0x9C,  0xF0,  0x80,  0x01,  0x00,  0xF0,  0x44,  0x0A,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x72,  0x01,  0xD6,  0x11,  0x00,  0x00,  0x70,  0x01,
-  0x30,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x90,  0x10,  0x2D,  0x03,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x48,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,  0x01,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x78,  0x56,  0x34,  0x12,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x04,  0xF7,  0x70,  0x01,  0x0C,  0x1C,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF2,  0xD6,  0x0A,
-  0x04,  0xF7,  0x70,  0x01,  0x06,  0xF7,  0x02,  0x00,  0x3E,  0x57,  0x3C,  0x56,  0x0C,  0x1C,  0x00,  0xFC,
-  0xA6,  0x00,  0x01,  0x58,  0xAA,  0x13,  0x20,  0xF0,  0xA6,  0x03,  0x06,  0xEC,  0xB9,  0x00,  0x0E,  0x47,
-  0x03,  0xE6,  0x10,  0x00,  0xCE,  0x45,  0x02,  0x13,  0x3E,  0x57,  0x06,  0xEA,  0xB9,  0x00,  0x47,  0x4B,
-  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x01,  0x48,  0x4E,  0x12,  0x03,  0xF6,  0xC0,  0x00,
-  0x00,  0xF2,  0x68,  0x0A,  0x41,  0x58,  0x03,  0xF6,  0xD0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x49,  0x44,
-  0x59,  0xF0,  0x0A,  0x02,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x44,  0x58,  0x00,  0xF2,
-  0xE2,  0x0D,  0x02,  0xCC,  0x4A,  0xE4,  0x01,  0x00,  0x55,  0xF0,  0x08,  0x03,  0x45,  0xF4,  0x02,  0x00,
-  0x83,  0x5A,  0x04,  0xCC,  0x01,  0x4A,  0x12,  0x12,  0x00,  0xF2,  0xE2,  0x0D,  0x00,  0xCD,  0x48,  0xE4,
-  0x01,  0x00,  0xE9,  0x13,  0x00,  0xF2,  0xC6,  0x0F,  0xFA,  0x10,  0x0E,  0x47,  0x03,  0xE6,  0x10,  0x00,
-  0xCE,  0x45,  0x02,  0x13,  0x3E,  0x57,  0xCE,  0x47,  0x97,  0x13,  0x04,  0xEC,  0xB4,  0x00,  0x00,  0xF2,
-  0xE2,  0x0D,  0x00,  0xCD,  0x48,  0xE4,  0x00,  0x00,  0x12,  0x12,  0x3E,  0x57,  0x06,  0xCC,  0x45,  0xF4,
-  0x02,  0x00,  0x83,  0x5A,  0x00,  0xCC,  0x00,  0xEA,  0xB4,  0x00,  0x92,  0x10,  0x00,  0xF0,  0x8C,  0x01,
-  0x43,  0xF0,  0x5C,  0x02,  0x44,  0xF0,  0x60,  0x02,  0x45,  0xF0,  0x64,  0x02,  0x46,  0xF0,  0x68,  0x02,
-  0x47,  0xF0,  0x6E,  0x02,  0x48,  0xF0,  0x9E,  0x02,  0xB9,  0x54,  0x62,  0x10,  0x00,  0x1C,  0x5A,  0x10,
-  0x02,  0x1C,  0x56,  0x10,  0x1E,  0x1C,  0x52,  0x10,  0x00,  0xF2,  0x1E,  0x11,  0x50,  0x10,  0x06,  0xFC,
-  0xA8,  0x00,  0x03,  0xF6,  0xBE,  0x00,  0x00,  0xF2,  0x4E,  0x0A,  0x8C,  0x10,  0x01,  0xF6,  0x01,  0x00,
-  0x01,  0xFA,  0xA8,  0x00,  0x00,  0xF2,  0x2C,  0x0B,  0x06,  0x10,  0xB9,  0x54,  0x01,  0xFA,  0xA8,  0x00,
-  0x03,  0xF6,  0xBE,  0x00,  0x00,  0xF2,  0x58,  0x0A,  0x01,  0xFC,  0xA8,  0x00,  0x20,  0x10,  0x58,  0x1C,
-  0x00,  0xF2,  0x1C,  0x0B,  0x5A,  0x1C,  0x01,  0xF6,  0x01,  0x00,  0x38,  0x54,  0x00,  0xFA,  0xA6,  0x00,
-  0x01,  0xFA,  0xA8,  0x00,  0x20,  0x1C,  0x00,  0xF0,  0x72,  0x01,  0x01,  0xF6,  0x01,  0x00,  0x38,  0x54,
-  0x00,  0xFA,  0xA6,  0x00,  0x01,  0xFA,  0xA8,  0x00,  0x20,  0x1C,  0x00,  0xF0,  0x80,  0x01,  0x03,  0xF6,
-  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x01,  0x48,  0x0A,  0x13,  0x00,  0xF2,  0x38,  0x10,  0x00,  0xF2,
-  0x54,  0x0F,  0x24,  0x10,  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x02,  0xF6,  0xD0,  0x00,
-  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x49,  0x44,  0x5B,  0xF0,  0x04,  0x03,  0x00,  0xF2,  0x9C,  0x0F,
-  0x00,  0xF0,  0x80,  0x01,  0x00,  0xF2,  0x14,  0x10,  0x0C,  0x1C,  0x02,  0x4B,  0xBF,  0x57,  0x9E,  0x43,
-  0x77,  0x57,  0x07,  0x4B,  0x20,  0xF0,  0xA6,  0x03,  0x40,  0x1C,  0x1E,  0xF0,  0x30,  0x03,  0x26,  0xF0,
-  0x2C,  0x03,  0xA0,  0xF0,  0x1A,  0x03,  0x11,  0xF0,  0xA6,  0x03,  0x12,  0x10,  0x9F,  0xF0,  0x3E,  0x03,
-  0x46,  0x1C,  0x82,  0xE7,  0x05,  0x00,  0x9E,  0xE7,  0x11,  0x00,  0x00,  0xF0,  0x06,  0x0A,  0x0C,  0x1C,
-  0x48,  0x1C,  0x46,  0x1C,  0x38,  0x54,  0x00,  0xEC,  0xBA,  0x00,  0x08,  0x44,  0x00,  0xEA,  0xBA,  0x00,
-  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x08,  0x44,  0x00,  0x4C,  0x82,  0xE7,  0x02,  0x00,
-  0x00,  0xF2,  0x12,  0x11,  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0x70,  0x03,  0x00,  0xF2,  0x60,  0x0B,
-  0x06,  0xF0,  0x80,  0x03,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,  0xFC,  0x09,  0x00,  0xF0,  0x02,  0x0A,
-  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0x55,  0xF0,  0xAC,  0x04,  0x01,  0xE6,  0x0C,  0x00,  0x00,  0xF2,
-  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,  0x01,  0xF0,
-  0x7C,  0x02,  0x00,  0xF0,  0x8A,  0x02,  0x46,  0x1C,  0x0C,  0x1C,  0x67,  0x1B,  0xBF,  0x57,  0x77,  0x57,
-  0x02,  0x4B,  0x48,  0x1C,  0x32,  0x1C,  0x00,  0xF2,  0x92,  0x0D,  0x30,  0x1C,  0x96,  0xF0,  0xBC,  0x03,
-  0xB1,  0xF0,  0xC0,  0x03,  0x1E,  0xF0,  0xFC,  0x09,  0x85,  0xF0,  0x02,  0x0A,  0x00,  0xFC,  0xBE,  0x00,
-  0x98,  0x57,  0x14,  0x12,  0x01,  0xE6,  0x0C,  0x00,  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,
-  0x01,  0xF0,  0x7C,  0x02,  0x00,  0xF0,  0x8A,  0x02,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,
-  0x01,  0x48,  0x55,  0xF0,  0x98,  0x04,  0x03,  0x82,  0x03,  0xFC,  0xA0,  0x00,  0x9B,  0x57,  0x40,  0x12,
-  0x69,  0x18,  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0x42,  0x04,  0x69,  0x08,  0x00,  0xF2,  0x12,  0x11,
-  0x85,  0xF0,  0x02,  0x0A,  0x68,  0x08,  0x4C,  0x44,  0x28,  0x12,  0x44,  0x48,  0x03,  0xF6,  0xE0,  0x00,
-  0x00,  0xF2,  0x68,  0x0A,  0x45,  0x58,  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0xCC,  0x01,  0x48,  0x55,  0xF0,
-  0x98,  0x04,  0x4C,  0x44,  0xEF,  0x13,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,  0x14,  0x10,  0x08,  0x10,
-  0x68,  0x18,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,  0x04,  0x80,  0x18,  0xE4,  0x10,  0x00,  0x28,  0x12,
-  0x01,  0xE6,  0x06,  0x00,  0x04,  0x80,  0x18,  0xE4,  0x01,  0x00,  0x04,  0x12,  0x01,  0xE6,  0x0D,  0x00,
-  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,  0x04,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,
-  0x01,  0xF0,  0x1C,  0x0A,  0x00,  0xF0,  0x02,  0x0A,  0x69,  0x08,  0x05,  0x80,  0x48,  0xE4,  0x00,  0x00,
-  0x0C,  0x12,  0x00,  0xE6,  0x11,  0x00,  0x00,  0xEA,  0xB8,  0x00,  0x00,  0xF2,  0xB6,  0x10,  0x82,  0xE7,
-  0x02,  0x00,  0x1C,  0x90,  0x40,  0x5C,  0x00,  0x16,  0x01,  0xE6,  0x06,  0x00,  0x00,  0xF2,  0x4E,  0x0D,
-  0x01,  0xF0,  0x80,  0x01,  0x1E,  0xF0,  0x80,  0x01,  0x00,  0xF0,  0xA0,  0x04,  0x42,  0x5B,  0x06,  0xF7,
-  0x03,  0x00,  0x46,  0x59,  0xBF,  0x57,  0x77,  0x57,  0x01,  0xE6,  0x80,  0x00,  0x07,  0x80,  0x31,  0x44,
-  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x56,  0x13,  0x20,  0x80,  0x48,  0xE4,  0x03,  0x00,  0x4E,  0x12,
-  0x00,  0xFC,  0xA2,  0x00,  0x98,  0x57,  0x55,  0xF0,  0x1C,  0x05,  0x31,  0xE4,  0x40,  0x00,  0x00,  0xFC,
-  0xA0,  0x00,  0x98,  0x57,  0x36,  0x12,  0x4C,  0x1C,  0x00,  0xF2,  0x12,  0x11,  0x89,  0x48,  0x00,  0xF2,
-  0x12,  0x11,  0x86,  0xF0,  0x2E,  0x05,  0x82,  0xE7,  0x06,  0x00,  0x1B,  0x80,  0x48,  0xE4,  0x22,  0x00,
-  0x5B,  0xF0,  0x0C,  0x05,  0x48,  0xE4,  0x20,  0x00,  0x59,  0xF0,  0x10,  0x05,  0x00,  0xE6,  0x20,  0x00,
-  0x09,  0x48,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0x2E,  0x05,  0x83,  0x80,  0x04,  0x10,  0x00,  0xF2,
-  0xA2,  0x0D,  0x00,  0xE6,  0x01,  0x00,  0x00,  0xEA,  0x26,  0x01,  0x01,  0xEA,  0x27,  0x01,  0x04,  0x80,
-  0x18,  0xE4,  0x10,  0x00,  0x36,  0x12,  0xB9,  0x54,  0x00,  0xF2,  0xF6,  0x0E,  0x01,  0xE6,  0x06,  0x00,
-  0x04,  0x80,  0x18,  0xE4,  0x01,  0x00,  0x04,  0x12,  0x01,  0xE6,  0x0D,  0x00,  0x00,  0xF2,  0x4E,  0x0D,
-  0x00,  0xF2,  0x12,  0x11,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,  0x04,  0xE6,  0x02,  0x00,
-  0x9E,  0xE7,  0x15,  0x00,  0x01,  0xF0,  0x1C,  0x0A,  0x00,  0xF0,  0x02,  0x0A,  0x00,  0xFC,  0x20,  0x01,
-  0x98,  0x57,  0x34,  0x12,  0x00,  0xFC,  0x24,  0x01,  0x98,  0x57,  0x2C,  0x13,  0xB9,  0x54,  0x00,  0xF2,
-  0xF6,  0x0E,  0x86,  0xF0,  0xA8,  0x05,  0x03,  0xF6,  0x01,  0x00,  0x00,  0xF2,  0x8C,  0x0E,  0x85,  0xF0,
-  0x9E,  0x05,  0x82,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x60,  0x0B,  0x82,  0xE7,  0x02,  0x00,  0x00,  0xFC,
-  0x24,  0x01,  0xB0,  0x57,  0x00,  0xFA,  0x24,  0x01,  0x00,  0xFC,  0x9E,  0x00,  0x98,  0x57,  0x5A,  0x12,
-  0x00,  0xFC,  0xB6,  0x00,  0x98,  0x57,  0x52,  0x13,  0x03,  0xE6,  0x0C,  0x00,  0x00,  0xFC,  0x9C,  0x00,
-  0x98,  0x57,  0x04,  0x13,  0x03,  0xE6,  0x19,  0x00,  0x05,  0xE6,  0x08,  0x00,  0x00,  0xF6,  0x00,  0x01,
-  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,  0x00,  0x80,  0x04,  0x13,  0x05,  0xE6,
-  0x0F,  0x00,  0xB9,  0x54,  0x00,  0xF2,  0xF6,  0x0E,  0x86,  0xF0,  0x0A,  0x06,  0x00,  0xF2,  0xBA,  0x0E,
-  0x85,  0xF0,  0x00,  0x06,  0x82,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x60,  0x0B,  0x82,  0xE7,  0x02,  0x00,
-  0x00,  0xFC,  0xB6,  0x00,  0xB0,  0x57,  0x00,  0xFA,  0xB6,  0x00,  0x01,  0xF6,  0x01,  0x00,  0x00,  0xF2,
-  0xF6,  0x0E,  0x9C,  0x32,  0x4E,  0x1C,  0x32,  0x1C,  0x00,  0xF2,  0x92,  0x0D,  0x30,  0x1C,  0x82,  0xE7,
-  0x04,  0x00,  0xB1,  0xF0,  0x22,  0x06,  0x0A,  0xF0,  0x3E,  0x06,  0x05,  0xF0,  0xD6,  0x06,  0x06,  0xF0,
-  0xDC,  0x06,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,  0xFC,  0x09,  0x00,  0xF0,  0x02,  0x0A,  0x04,  0x80,
-  0x18,  0xE4,  0x20,  0x00,  0x30,  0x12,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x21,  0x80,
-  0x18,  0xE4,  0xE0,  0x00,  0x09,  0x48,  0x00,  0xF2,  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,
-  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x99,  0xA4,  0x00,  0xF2,  0x12,  0x11,
-  0x09,  0xE7,  0x00,  0x00,  0x9A,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x34,  0x12,  0x09,  0xE7,
-  0x1B,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x21,  0x80,  0x18,  0xE4,  0xE0,  0x00,  0x09,  0x48,  0x00,  0xF2,
-  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF2,
-  0x12,  0x11,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x09,  0xE7,  0x00,  0x00,  0x00,  0xF0,
-  0x0C,  0x09,  0xBB,  0x55,  0x9A,  0x81,  0x03,  0xF7,  0x20,  0x00,  0x09,  0x6F,  0x93,  0x45,  0x55,  0xF0,
-  0xE2,  0x06,  0xB1,  0xF0,  0xC2,  0x06,  0x0A,  0xF0,  0xBA,  0x06,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,
-  0xFC,  0x09,  0x00,  0xF0,  0x02,  0x0A,  0x00,  0xF2,  0x60,  0x0B,  0x47,  0x10,  0x09,  0xE7,  0x08,  0x00,
-  0x41,  0x10,  0x05,  0x80,  0x48,  0xE4,  0x00,  0x00,  0x1E,  0x12,  0x00,  0xE6,  0x11,  0x00,  0x00,  0xEA,
-  0xB8,  0x00,  0x00,  0xF2,  0xB6,  0x10,  0x2C,  0x90,  0xAE,  0x90,  0x08,  0x50,  0x8A,  0x50,  0x38,  0x54,
-  0x1F,  0x40,  0x00,  0xF2,  0xB4,  0x0D,  0x08,  0x10,  0x08,  0x90,  0x8A,  0x90,  0x30,  0x50,  0xB2,  0x50,
-  0x9C,  0x32,  0x0C,  0x92,  0x8E,  0x92,  0x38,  0x54,  0x04,  0x80,  0x30,  0xE4,  0x08,  0x00,  0x04,  0x40,
-  0x0C,  0x1C,  0x00,  0xF6,  0x03,  0x00,  0xB1,  0xF0,  0x26,  0x07,  0x9E,  0xF0,  0x3A,  0x07,  0x01,  0x48,
-  0x55,  0xF0,  0xFC,  0x09,  0x0C,  0x1C,  0x10,  0x44,  0xED,  0x10,  0x0B,  0xF0,  0x5E,  0x07,  0x0C,  0xF0,
-  0x62,  0x07,  0x05,  0xF0,  0x52,  0x07,  0x06,  0xF0,  0x58,  0x07,  0x09,  0xF0,  0x24,  0x09,  0x00,  0xF0,
-  0x02,  0x0A,  0x00,  0xF2,  0x60,  0x0B,  0xCF,  0x10,  0x09,  0xE7,  0x08,  0x00,  0xC9,  0x10,  0x2E,  0x1C,
-  0x02,  0x10,  0x2C,  0x1C,  0xAA,  0xF0,  0x64,  0x07,  0xAC,  0xF0,  0x72,  0x07,  0x40,  0x10,  0x34,  0x1C,
-  0xF3,  0x10,  0xAD,  0xF0,  0x7C,  0x07,  0xC8,  0x10,  0x36,  0x1C,  0xE9,  0x10,  0x2B,  0xF0,  0x82,  0x08,
-  0x6B,  0x18,  0x18,  0xF4,  0x00,  0xFE,  0x20,  0x12,  0x01,  0x58,  0xD2,  0xF0,  0x82,  0x08,  0x76,  0x18,
-  0x18,  0xF4,  0x03,  0x00,  0xEC,  0x12,  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0xE2,  0x12,
-  0x0B,  0xF0,  0x64,  0x07,  0x0C,  0xF0,  0x64,  0x07,  0x36,  0x1C,  0x34,  0x1C,  0xB7,  0x10,  0x38,  0x54,
-  0xB9,  0x54,  0x84,  0x80,  0x19,  0xE4,  0x20,  0x00,  0xB2,  0x13,  0x85,  0x80,  0x81,  0x48,  0x66,  0x12,
-  0x04,  0x80,  0x18,  0xE4,  0x08,  0x00,  0x58,  0x13,  0x1F,  0x80,  0x08,  0x44,  0xC8,  0x44,  0x9F,  0x12,
-  0x1F,  0x40,  0x34,  0x91,  0xB6,  0x91,  0x44,  0x55,  0xE5,  0x55,  0x02,  0xEC,  0xB8,  0x00,  0x02,  0x49,
-  0xBB,  0x55,  0x82,  0x81,  0xC0,  0x55,  0x48,  0xF4,  0x0F,  0x00,  0x5A,  0xF0,  0x1A,  0x08,  0x4A,  0xE4,
-  0x17,  0x00,  0xD5,  0xF0,  0xFA,  0x07,  0x02,  0xF6,  0x0F,  0x00,  0x02,  0xF4,  0x02,  0x00,  0x02,  0xEA,
-  0xB8,  0x00,  0x04,  0x91,  0x86,  0x91,  0x02,  0x4B,  0x2C,  0x90,  0x08,  0x50,  0x2E,  0x90,  0x0A,  0x50,
-  0x2C,  0x51,  0xAE,  0x51,  0x00,  0xF2,  0xB6,  0x10,  0x38,  0x54,  0x00,  0xF2,  0xB4,  0x0D,  0x56,  0x10,
-  0x34,  0x91,  0xB6,  0x91,  0x0C,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x08,  0x00,  0x41,  0x12,  0x0C,  0x91,
-  0x8E,  0x91,  0x04,  0x80,  0x18,  0xE4,  0xF7,  0x00,  0x04,  0x40,  0x30,  0x90,  0xB2,  0x90,  0x36,  0x10,
-  0x02,  0x80,  0x48,  0xE4,  0x10,  0x00,  0x31,  0x12,  0x82,  0xE7,  0x10,  0x00,  0x84,  0x80,  0x19,  0xE4,
-  0x20,  0x00,  0x10,  0x13,  0x0C,  0x90,  0x8E,  0x90,  0x5D,  0xF0,  0x78,  0x07,  0x0C,  0x58,  0x8D,  0x58,
-  0x00,  0xF0,  0x64,  0x07,  0x38,  0x54,  0xB9,  0x54,  0x19,  0x80,  0xF1,  0x10,  0x3A,  0x55,  0x19,  0x81,
-  0xBB,  0x55,  0x10,  0x90,  0x92,  0x90,  0x10,  0x58,  0x91,  0x58,  0x14,  0x59,  0x95,  0x59,  0x00,  0xF0,
-  0x64,  0x07,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x06,  0x12,  0x6C,  0x19,  0x19,  0x41,  0x7C,  0x10,
-  0x6C,  0x19,  0x0C,  0x51,  0xED,  0x19,  0x8E,  0x51,  0x6B,  0x18,  0x18,  0xF4,  0x00,  0xFF,  0x02,  0x13,
-  0x6A,  0x10,  0x01,  0x58,  0xD2,  0xF0,  0xC0,  0x08,  0x76,  0x18,  0x18,  0xF4,  0x03,  0x00,  0x0A,  0x12,
-  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0x06,  0x13,  0x9E,  0xE7,  0x16,  0x00,  0x4C,  0x10,
-  0xD1,  0xF0,  0xCA,  0x08,  0x9E,  0xE7,  0x17,  0x00,  0x42,  0x10,  0xD0,  0xF0,  0xD4,  0x08,  0x9E,  0xE7,
-  0x19,  0x00,  0x38,  0x10,  0xCF,  0xF0,  0xDE,  0x08,  0x9E,  0xE7,  0x20,  0x00,  0x2E,  0x10,  0xCE,  0xF0,
-  0xE8,  0x08,  0x9E,  0xE7,  0x21,  0x00,  0x24,  0x10,  0xCD,  0xF0,  0xF2,  0x08,  0x9E,  0xE7,  0x22,  0x00,
-  0x1A,  0x10,  0xCC,  0xF0,  0x04,  0x09,  0x84,  0x80,  0x19,  0xE4,  0x04,  0x00,  0x06,  0x12,  0x9E,  0xE7,
-  0x12,  0x00,  0x08,  0x10,  0xCB,  0xF0,  0x0C,  0x09,  0x9E,  0xE7,  0x24,  0x00,  0xB1,  0xF0,  0x0C,  0x09,
-  0x05,  0xF0,  0x1E,  0x09,  0x09,  0xF0,  0x24,  0x09,  0x1E,  0xF0,  0xFC,  0x09,  0xE4,  0x10,  0x00,  0xF2,
-  0x60,  0x0B,  0xE9,  0x10,  0x9C,  0x32,  0x82,  0xE7,  0x20,  0x00,  0x32,  0x1C,  0xE9,  0x09,  0x00,  0xF2,
-  0x12,  0x11,  0x85,  0xF0,  0x02,  0x0A,  0x69,  0x08,  0x01,  0xF0,  0x44,  0x09,  0x1E,  0xF0,  0xFC,  0x09,
-  0x00,  0xF0,  0x38,  0x09,  0x30,  0x44,  0x06,  0x12,  0x9E,  0xE7,  0x42,  0x00,  0xB8,  0x10,  0x04,  0xF6,
-  0x01,  0x00,  0xB3,  0x45,  0x74,  0x12,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,  0x22,  0x13,  0x4B,  0xE4,
-  0x02,  0x00,  0x36,  0x12,  0x4B,  0xE4,  0x28,  0x00,  0xAC,  0x13,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,
-  0xC8,  0x11,  0x03,  0xF6,  0xD0,  0x00,  0xFA,  0x14,  0x82,  0xE7,  0x01,  0x00,  0x00,  0xF0,  0x80,  0x01,
-  0x9E,  0xE7,  0x44,  0x00,  0x4B,  0xE4,  0x02,  0x00,  0x06,  0x12,  0x03,  0xE6,  0x02,  0x00,  0x76,  0x10,
-  0x00,  0xF2,  0xA2,  0x0D,  0x03,  0xE6,  0x02,  0x00,  0x6C,  0x10,  0x00,  0xF2,  0xA2,  0x0D,  0x19,  0x82,
-  0x34,  0x46,  0x0A,  0x13,  0x03,  0xE6,  0x02,  0x00,  0x9E,  0xE7,  0x43,  0x00,  0x68,  0x10,  0x04,  0x80,
-  0x30,  0xE4,  0x20,  0x00,  0x04,  0x40,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,  0x82,  0xE7,
-  0x01,  0x00,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF0,  0x08,  0x03,  0x04,  0x80,  0x18,  0xE4,  0x20,  0x00,
-  0x06,  0x12,  0x03,  0xE6,  0x02,  0x00,  0x3E,  0x10,  0x04,  0x80,  0x18,  0xE4,  0x02,  0x00,  0x3A,  0x12,
-  0x04,  0x80,  0x18,  0xE4,  0xFD,  0x00,  0x04,  0x40,  0x1C,  0x1C,  0x9D,  0xF0,  0xEA,  0x09,  0x1C,  0x1C,
-  0x9D,  0xF0,  0xF0,  0x09,  0xC1,  0x10,  0x9E,  0xE7,  0x13,  0x00,  0x0A,  0x10,  0x9E,  0xE7,  0x41,  0x00,
-  0x04,  0x10,  0x9E,  0xE7,  0x24,  0x00,  0x00,  0xFC,  0xBE,  0x00,  0x98,  0x57,  0xD5,  0xF0,  0x8A,  0x02,
-  0x04,  0xE6,  0x04,  0x00,  0x06,  0x10,  0x04,  0xE6,  0x04,  0x00,  0x9D,  0x41,  0x1C,  0x42,  0x9F,  0xE7,
-  0x00,  0x00,  0x06,  0xF7,  0x02,  0x00,  0x03,  0xF6,  0xE0,  0x00,  0x3C,  0x14,  0x44,  0x58,  0x45,  0x58,
-  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0xF2,  0x7E,  0x10,  0x00,  0xF2,  0xC6,  0x0F,  0x3C,  0x14,  0x1E,  0x1C,
-  0x00,  0xF0,  0x80,  0x01,  0x12,  0x1C,  0x22,  0x1C,  0xD2,  0x14,  0x00,  0xF0,  0x72,  0x01,  0x83,  0x59,
-  0x03,  0xDC,  0x73,  0x57,  0x80,  0x5D,  0x00,  0x16,  0x83,  0x59,  0x03,  0xDC,  0x38,  0x54,  0x70,  0x57,
-  0x33,  0x54,  0x3B,  0x54,  0x80,  0x5D,  0x00,  0x16,  0x03,  0x57,  0x83,  0x59,  0x38,  0x54,  0x00,  0xCC,
-  0x00,  0x16,  0x03,  0x57,  0x83,  0x59,  0x00,  0x4C,  0x00,  0x16,  0x02,  0x80,  0x48,  0xE4,  0x01,  0x00,
-  0x0E,  0x12,  0x48,  0xE4,  0x05,  0x00,  0x08,  0x12,  0x00,  0xF2,  0xBC,  0x11,  0x00,  0xF2,  0xC8,  0x11,
-  0xC1,  0x5A,  0x3A,  0x55,  0x02,  0xEC,  0xB5,  0x00,  0x45,  0x59,  0x00,  0xF2,  0xF6,  0x0D,  0x83,  0x58,
-  0x30,  0xE7,  0x00,  0x00,  0x10,  0x4D,  0x30,  0xE7,  0x40,  0x00,  0x10,  0x4F,  0x38,  0x90,  0xBA,  0x90,
-  0x10,  0x5C,  0x80,  0x5C,  0x83,  0x5A,  0x10,  0x4E,  0x04,  0xEA,  0xB5,  0x00,  0x43,  0x5B,  0x03,  0xF4,
-  0xE0,  0x00,  0x83,  0x59,  0x04,  0xCC,  0x01,  0x4A,  0x0A,  0x12,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,
-  0x00,  0xF2,  0x38,  0x10,  0x00,  0x16,  0x08,  0x1C,  0x00,  0xFC,  0xAC,  0x00,  0x06,  0x58,  0x67,  0x18,
-  0x18,  0xF4,  0x8F,  0xE1,  0x01,  0xFC,  0xAE,  0x00,  0x19,  0xF4,  0x70,  0x1E,  0xB0,  0x54,  0x07,  0x58,
-  0x00,  0xFC,  0xB0,  0x00,  0x08,  0x58,  0x00,  0xFC,  0xB2,  0x00,  0x09,  0x58,  0x0A,  0x1C,  0x00,  0xE6,
-  0x0F,  0x00,  0x00,  0xEA,  0xB9,  0x00,  0x38,  0x54,  0x00,  0xFA,  0x24,  0x01,  0x00,  0xFA,  0xB6,  0x00,
-  0x18,  0x1C,  0x14,  0x1C,  0x10,  0x1C,  0x32,  0x1C,  0x12,  0x1C,  0x00,  0x16,  0x3E,  0x57,  0x0C,  0x14,
-  0x0E,  0x47,  0x07,  0xE6,  0x10,  0x00,  0xCE,  0x47,  0xF5,  0x13,  0x00,  0x16,  0x00,  0xF2,  0xA2,  0x0D,
-  0x02,  0x4B,  0x03,  0xF6,  0xE0,  0x00,  0x00,  0xF2,  0x68,  0x0A,  0x01,  0x48,  0x20,  0x12,  0x44,  0x58,
-  0x45,  0x58,  0x9E,  0xE7,  0x15,  0x00,  0x9C,  0xE7,  0x04,  0x00,  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0xF2,
-  0x7E,  0x10,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,  0x7A,  0x0A,  0x1E,  0x1C,  0xD5,  0x10,  0x00,  0x16,
-  0x69,  0x08,  0x48,  0xE4,  0x04,  0x00,  0x64,  0x12,  0x48,  0xE4,  0x02,  0x00,  0x20,  0x12,  0x48,  0xE4,
-  0x03,  0x00,  0x1A,  0x12,  0x48,  0xE4,  0x08,  0x00,  0x14,  0x12,  0x48,  0xE4,  0x01,  0x00,  0xF0,  0x12,
-  0x48,  0xE4,  0x07,  0x00,  0x12,  0x12,  0x01,  0xE6,  0x07,  0x00,  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,
-  0x12,  0x11,  0x05,  0xF0,  0x60,  0x0B,  0x00,  0x16,  0x00,  0xE6,  0x01,  0x00,  0x00,  0xEA,  0x99,  0x00,
-  0x02,  0x80,  0x48,  0xE4,  0x03,  0x00,  0xE7,  0x12,  0x48,  0xE4,  0x06,  0x00,  0xE1,  0x12,  0x01,  0xE6,
-  0x06,  0x00,  0x00,  0xF2,  0x4E,  0x0D,  0x00,  0xF2,  0x12,  0x11,  0x04,  0xE6,  0x02,  0x00,  0x9E,  0xE7,
-  0x15,  0x00,  0x01,  0xF0,  0x1C,  0x0A,  0x00,  0xF0,  0x02,  0x0A,  0x00,  0x16,  0x02,  0x80,  0x48,  0xE4,
-  0x10,  0x00,  0x1C,  0x12,  0x82,  0xE7,  0x08,  0x00,  0x3C,  0x56,  0x03,  0x82,  0x00,  0xF2,  0xE2,  0x0D,
-  0x30,  0xE7,  0x08,  0x00,  0x04,  0xF7,  0x70,  0x01,  0x06,  0xF7,  0x02,  0x00,  0x00,  0xF0,  0x80,  0x01,
-  0x6C,  0x19,  0xED,  0x19,  0x5D,  0xF0,  0xD4,  0x0B,  0x44,  0x55,  0xE5,  0x55,  0x59,  0xF0,  0x52,  0x0C,
-  0x04,  0x55,  0xA5,  0x55,  0x1F,  0x80,  0x01,  0xEC,  0xB8,  0x00,  0x82,  0x48,  0x82,  0x80,  0x49,  0x44,
-  0x2E,  0x13,  0x01,  0xEC,  0xB8,  0x00,  0x41,  0xE4,  0x02,  0x00,  0x01,  0xEA,  0xB8,  0x00,  0x49,  0xE4,
-  0x11,  0x00,  0x59,  0xF0,  0x2E,  0x0C,  0x01,  0xE6,  0x17,  0x00,  0x01,  0xEA,  0xB8,  0x00,  0x02,  0x4B,
-  0x88,  0x90,  0xAC,  0x50,  0x8A,  0x90,  0xAE,  0x50,  0x01,  0xEC,  0xB8,  0x00,  0x82,  0x48,  0x82,  0x80,
-  0x10,  0x44,  0x02,  0x4B,  0x1F,  0x40,  0xC0,  0x44,  0x00,  0xF2,  0xB4,  0x0D,  0x04,  0x55,  0xA5,  0x55,
-  0x9F,  0x10,  0x0C,  0x51,  0x8E,  0x51,  0x30,  0x90,  0xB2,  0x90,  0x00,  0x56,  0xA1,  0x56,  0x30,  0x50,
-  0xB2,  0x50,  0x34,  0x90,  0xB6,  0x90,  0x40,  0x56,  0xE1,  0x56,  0x34,  0x50,  0xB6,  0x50,  0x65,  0x10,
-  0xB1,  0xF0,  0x70,  0x0C,  0x85,  0xF0,  0xCA,  0x0B,  0xE9,  0x09,  0x4B,  0xE4,  0x03,  0x00,  0x78,  0x12,
-  0x4B,  0xE4,  0x02,  0x00,  0x01,  0x13,  0xB1,  0xF0,  0x86,  0x0C,  0x85,  0xF0,  0xCA,  0x0B,  0x69,  0x08,
-  0x48,  0xE4,  0x03,  0x00,  0xD5,  0xF0,  0x86,  0x0B,  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0xCA,  0x0B,
-  0xE8,  0x09,  0x3C,  0x56,  0x00,  0xFC,  0x20,  0x01,  0x98,  0x57,  0x02,  0x13,  0xBB,  0x45,  0x4B,  0xE4,
-  0x00,  0x00,  0x08,  0x12,  0x03,  0xE6,  0x01,  0x00,  0x04,  0xF6,  0x00,  0x80,  0xA8,  0x14,  0xD2,  0x14,
-  0x30,  0x1C,  0x02,  0x80,  0x48,  0xE4,  0x03,  0x00,  0x10,  0x13,  0x00,  0xFC,  0xB6,  0x00,  0x98,  0x57,
-  0x02,  0x13,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF0,  0x8E,  0x0B,  0x00,  0xFC,  0x24,  0x01,  0xB0,  0x57,
-  0x00,  0xFA,  0x24,  0x01,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0x8E,  0x0B,
-  0x00,  0xF2,  0x8C,  0x0E,  0x00,  0xF0,  0x8E,  0x0B,  0xB1,  0xF0,  0xF8,  0x0C,  0x85,  0xF0,  0x86,  0x0B,
-  0x69,  0x08,  0x48,  0xE4,  0x01,  0x00,  0xD5,  0xF0,  0x86,  0x0B,  0xFC,  0x14,  0x42,  0x58,  0x6C,  0x14,
-  0x80,  0x14,  0x30,  0x1C,  0x4A,  0xF4,  0x02,  0x00,  0x55,  0xF0,  0x86,  0x0B,  0x4A,  0xF4,  0x01,  0x00,
-  0x0E,  0x12,  0x02,  0x80,  0x48,  0xE4,  0x03,  0x00,  0x06,  0x13,  0x3E,  0x1C,  0x00,  0xF0,  0x8E,  0x0B,
-  0x00,  0xFC,  0xB6,  0x00,  0xB0,  0x57,  0x00,  0xFA,  0xB6,  0x00,  0x4C,  0x1C,  0x3E,  0x1C,  0x00,  0xF2,
-  0x12,  0x11,  0x86,  0xF0,  0x8E,  0x0B,  0x00,  0xF2,  0xBA,  0x0E,  0x00,  0xF0,  0x8E,  0x0B,  0x4C,  0x1C,
-  0xB1,  0xF0,  0x50,  0x0D,  0x85,  0xF0,  0x5C,  0x0D,  0x69,  0x08,  0xF3,  0x10,  0x86,  0xF0,  0x64,  0x0D,
-  0x4E,  0x1C,  0x89,  0x48,  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,
-  0x00,  0xDC,  0x18,  0xF4,  0xFF,  0x7F,  0x30,  0x56,  0x00,  0x5C,  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,
-  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x18,  0xF4,  0x00,  0x80,  0x30,  0x56,  0x00,  0x5C,
-  0x00,  0x16,  0x00,  0xF6,  0x00,  0x01,  0x00,  0x57,  0x00,  0x57,  0x03,  0x58,  0x00,  0xDC,  0x0B,  0x58,
-  0x00,  0x16,  0x03,  0xF6,  0x24,  0x01,  0x00,  0xF2,  0x58,  0x0A,  0x03,  0xF6,  0xB6,  0x00,  0x00,  0xF2,
-  0x58,  0x0A,  0x00,  0x16,  0x02,  0xEC,  0xB8,  0x00,  0x02,  0x49,  0x18,  0xF4,  0xFF,  0x00,  0x00,  0x54,
-  0x00,  0x54,  0x00,  0x54,  0x00,  0xF4,  0x08,  0x00,  0xE1,  0x18,  0x80,  0x54,  0x03,  0x58,  0x00,  0xDD,
-  0x01,  0xDD,  0x02,  0xDD,  0x03,  0xDC,  0x02,  0x4B,  0x30,  0x50,  0xB2,  0x50,  0x34,  0x51,  0xB6,  0x51,
-  0x00,  0x16,  0x45,  0x5A,  0x1D,  0xF4,  0xFF,  0x00,  0x85,  0x56,  0x85,  0x56,  0x85,  0x56,  0x05,  0xF4,
-  0x02,  0x12,  0x83,  0x5A,  0x00,  0x16,  0x1D,  0xF4,  0xFF,  0x00,  0x85,  0x56,  0x85,  0x56,  0x85,  0x56,
-  0x05,  0xF4,  0x00,  0x12,  0x83,  0x5A,  0x00,  0x16,  0x38,  0x54,  0xBB,  0x55,  0x3C,  0x56,  0xBD,  0x56,
-  0x00,  0xF2,  0x12,  0x11,  0x85,  0xF0,  0x82,  0x0E,  0xE9,  0x09,  0xC1,  0x59,  0x00,  0xF2,  0x12,  0x11,
-  0x85,  0xF0,  0x82,  0x0E,  0xE8,  0x0A,  0x83,  0x55,  0x83,  0x55,  0x4B,  0xF4,  0x90,  0x01,  0x5C,  0xF0,
-  0x36,  0x0E,  0xBD,  0x56,  0x40,  0x10,  0x4B,  0xF4,  0x30,  0x00,  0x59,  0xF0,  0x48,  0x0E,  0x01,  0xF6,
-  0x0C,  0x00,  0x00,  0xF6,  0x01,  0x00,  0x2E,  0x10,  0x02,  0xFC,  0x9C,  0x00,  0x9A,  0x57,  0x14,  0x13,
-  0x4B,  0xF4,  0x64,  0x00,  0x59,  0xF0,  0x64,  0x0E,  0x03,  0xF6,  0x64,  0x00,  0x01,  0xF6,  0x19,  0x00,
-  0x00,  0xF6,  0x01,  0x00,  0x43,  0xF4,  0x33,  0x00,  0x56,  0xF0,  0x76,  0x0E,  0x04,  0xF4,  0x00,  0x01,
-  0x43,  0xF4,  0x19,  0x00,  0xF3,  0x10,  0xB4,  0x56,  0xC3,  0x58,  0x02,  0xFC,  0x9E,  0x00,  0x9A,  0x57,
-  0x08,  0x13,  0x3C,  0x56,  0x00,  0xF6,  0x02,  0x00,  0x00,  0x16,  0x00,  0x16,  0x09,  0xE7,  0x01,  0x00,
-  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xB8,  0x0E,  0x09,  0xE7,  0x02,  0x00,  0x00,  0xF2,  0x12,  0x11,
-  0x86,  0xF0,  0xB8,  0x0E,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xB8,  0x0E,
-  0x4E,  0x1C,  0x89,  0x49,  0x00,  0xF2,  0x12,  0x11,  0x00,  0x16,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,
-  0x12,  0x11,  0x86,  0xF0,  0xF2,  0x0E,  0x09,  0xE7,  0x03,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,
-  0xF2,  0x0E,  0x09,  0xE7,  0x01,  0x00,  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xF2,  0x0E,  0x89,  0x49,
-  0x00,  0xF2,  0x12,  0x11,  0x86,  0xF0,  0xF2,  0x0E,  0x4E,  0x1C,  0x89,  0x4A,  0x00,  0xF2,  0x12,  0x11,
-  0x00,  0x16,  0x3C,  0x56,  0x00,  0x16,  0x00,  0xEC,  0x26,  0x01,  0x48,  0xE4,  0x01,  0x00,  0x1E,  0x13,
-  0x38,  0x44,  0x00,  0xEA,  0x26,  0x01,  0x49,  0xF4,  0x00,  0x00,  0x04,  0x12,  0x4E,  0x1C,  0x02,  0x10,
-  0x4C,  0x1C,  0x01,  0xEC,  0x27,  0x01,  0x89,  0x48,  0x00,  0xF2,  0x12,  0x11,  0x02,  0x14,  0x00,  0x16,
-  0x85,  0xF0,  0x52,  0x0F,  0x38,  0x54,  0x00,  0xEA,  0x99,  0x00,  0x00,  0xF2,  0x60,  0x0B,  0x02,  0x80,
-  0x48,  0xE4,  0x06,  0x00,  0x1C,  0x13,  0x00,  0xEC,  0x99,  0x00,  0x48,  0xE4,  0x01,  0x00,  0x0A,  0x12,
-  0x04,  0x80,  0x30,  0xE4,  0x01,  0x00,  0x04,  0x40,  0x08,  0x10,  0x04,  0x80,  0x18,  0xE4,  0xFE,  0x00,
-  0x04,  0x40,  0x00,  0x16,  0x02,  0xF6,  0xE0,  0x00,  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x81,  0x48,
-  0x22,  0x12,  0x00,  0x4E,  0x83,  0x5A,  0x90,  0x4C,  0x20,  0xE7,  0x00,  0x00,  0xC3,  0x58,  0x1B,  0xF4,
-  0xFF,  0x00,  0x83,  0x55,  0x83,  0x55,  0x83,  0x55,  0x03,  0xF4,  0x00,  0x12,  0x8B,  0x55,  0x83,  0x59,
-  0x00,  0x4E,  0x00,  0x16,  0x00,  0x4E,  0x02,  0xF6,  0xF0,  0x00,  0x02,  0x57,  0x03,  0x59,  0x00,  0x4E,
-  0x83,  0x5A,  0x30,  0xE7,  0x00,  0x00,  0x20,  0xE7,  0x00,  0x00,  0x00,  0x16,  0x02,  0xF6,  0xF0,  0x00,
-  0x02,  0x57,  0x03,  0x59,  0x01,  0xCC,  0x00,  0x4E,  0x83,  0x5A,  0x30,  0xE7,  0x00,  0x00,  0x80,  0x4C,
-  0xC3,  0x58,  0x1B,  0xF4,  0xFF,  0x00,  0x83,  0x55,  0x83,  0x55,  0x83,  0x55,  0x03,  0xF4,  0x00,  0x12,
-  0x83,  0x59,  0x00,  0x4E,  0x00,  0x16,  0x03,  0xF6,  0xE0,  0x00,  0x03,  0x57,  0x83,  0x59,  0x3A,  0x55,
-  0x02,  0xCC,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,  0xC0,  0x5A,  0x40,  0x5C,  0x38,  0x54,  0x00,  0xCD,
-  0x01,  0xCC,  0x4A,  0x46,  0x0A,  0x13,  0x83,  0x59,  0x00,  0x4C,  0x01,  0x48,  0x16,  0x13,  0x0C,  0x10,
-  0xC5,  0x58,  0x00,  0xF2,  0xF6,  0x0D,  0x00,  0x4C,  0x01,  0x48,  0x08,  0x13,  0x05,  0xF6,  0xF0,  0x00,
-  0x05,  0x57,  0x08,  0x10,  0x45,  0x58,  0x00,  0xF2,  0xF6,  0x0D,  0x8D,  0x56,  0x83,  0x5A,  0x80,  0x4C,
-  0x05,  0x17,  0x00,  0x16,  0x02,  0x4B,  0x06,  0xF7,  0x04,  0x00,  0x62,  0x0B,  0x03,  0x82,  0x00,  0xF2,
-  0xE2,  0x0D,  0x02,  0x80,  0x00,  0x4C,  0x45,  0xF4,  0x02,  0x00,  0x52,  0x14,  0x06,  0xF7,  0x02,  0x00,
-  0x06,  0x14,  0x00,  0xF2,  0x54,  0x0F,  0x00,  0x16,  0x02,  0x4B,  0x01,  0xF6,  0xFF,  0x00,  0x38,  0x1C,
-  0x05,  0xF4,  0x04,  0x00,  0x83,  0x5A,  0x18,  0xDF,  0x19,  0xDF,  0x1D,  0xF7,  0x3C,  0x00,  0xB8,  0xF0,
-  0x4E,  0x10,  0x9C,  0x14,  0x01,  0x48,  0x1C,  0x13,  0x0E,  0xF7,  0x3C,  0x00,  0x03,  0xF7,  0x04,  0x00,
-  0xAF,  0x19,  0x03,  0x42,  0x45,  0xF4,  0x02,  0x00,  0x83,  0x5A,  0x02,  0xCC,  0x02,  0x41,  0x45,  0xF4,
-  0x02,  0x00,  0x00,  0x16,  0x91,  0x44,  0xD5,  0xF0,  0x3E,  0x10,  0x00,  0xF0,  0x9E,  0x02,  0x01,  0xF6,
-  0xFF,  0x00,  0x38,  0x1C,  0x05,  0xF4,  0x04,  0x00,  0x83,  0x5A,  0x18,  0xDF,  0x19,  0xDF,  0x0E,  0xF7,
-  0x3C,  0x00,  0x03,  0xF7,  0x04,  0x00,  0x0F,  0x79,  0x1C,  0xF7,  0x3C,  0x00,  0xB8,  0xF0,  0x9C,  0x10,
-  0x4E,  0x14,  0x01,  0x48,  0x06,  0x13,  0x45,  0xF4,  0x04,  0x00,  0x00,  0x16,  0x91,  0x44,  0xD5,  0xF0,
-  0x82,  0x10,  0x00,  0xF0,  0x9E,  0x02,  0x02,  0xF6,  0xFF,  0x00,  0x38,  0x1C,  0x2C,  0xBC,  0xAE,  0xBC,
-  0xE2,  0x08,  0x00,  0xEC,  0xB8,  0x00,  0x02,  0x48,  0x1D,  0xF7,  0x80,  0x00,  0xB8,  0xF0,  0xCC,  0x10,
-  0x1E,  0x14,  0x01,  0x48,  0x0E,  0x13,  0x0E,  0xF7,  0x80,  0x00,  0x38,  0x54,  0x03,  0x58,  0xAF,  0x19,
-  0x82,  0x48,  0x00,  0x16,  0x82,  0x48,  0x12,  0x45,  0xD5,  0xF0,  0xBA,  0x10,  0x00,  0xF0,  0x9E,  0x02,
-  0x39,  0xF0,  0xF8,  0x10,  0x38,  0x44,  0x00,  0x16,  0x7E,  0x18,  0x18,  0xF4,  0x03,  0x00,  0x04,  0x13,
-  0x61,  0x18,  0x00,  0x16,  0x38,  0x1C,  0x00,  0xFC,  0x22,  0x01,  0x18,  0xF4,  0x01,  0x00,  0xF1,  0x12,
-  0xE3,  0x10,  0x30,  0x44,  0x30,  0x44,  0x30,  0x44,  0xB1,  0xF0,  0x18,  0x11,  0x00,  0x16,  0x3E,  0x57,
-  0x03,  0xF6,  0xE0,  0x00,  0x03,  0x57,  0x83,  0x59,  0x04,  0xCC,  0x01,  0x4A,  0x6A,  0x12,  0x45,  0x5A,
-  0x00,  0xF2,  0xF6,  0x0D,  0x02,  0x4B,  0x70,  0x14,  0x34,  0x13,  0x02,  0x80,  0x48,  0xE4,  0x08,  0x00,
-  0x18,  0x12,  0x9C,  0xE7,  0x02,  0x00,  0x9E,  0xE7,  0x15,  0x00,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,
-  0x7A,  0x0A,  0x1E,  0x1C,  0x01,  0xF6,  0x01,  0x00,  0x00,  0x16,  0x30,  0xE4,  0x10,  0x00,  0x04,  0x40,
-  0x00,  0xF2,  0xE2,  0x0D,  0x20,  0xE7,  0x01,  0x00,  0x01,  0xF6,  0x01,  0x00,  0x00,  0x16,  0x04,  0xDC,
-  0x01,  0x4A,  0x24,  0x12,  0x45,  0x5A,  0x00,  0xF2,  0xF6,  0x0D,  0x43,  0x5B,  0x06,  0xEC,  0x98,  0x00,
-  0x00,  0xF2,  0x38,  0x10,  0xC6,  0x59,  0x20,  0x14,  0x0A,  0x13,  0x00,  0xF2,  0xC6,  0x0F,  0x00,  0xF2,
-  0x14,  0x10,  0xA7,  0x10,  0x83,  0x5A,  0xD7,  0x10,  0x0E,  0x47,  0x07,  0xE6,  0x10,  0x00,  0xCE,  0x47,
-  0x5A,  0xF0,  0x20,  0x11,  0xB9,  0x54,  0x00,  0x16,  0x14,  0x90,  0x96,  0x90,  0x02,  0xFC,  0xA8,  0x00,
-  0x03,  0xFC,  0xAA,  0x00,  0x48,  0x55,  0x02,  0x13,  0xC9,  0x55,  0x00,  0x16,  0x00,  0xEC,  0xBA,  0x00,
-  0x10,  0x44,  0x00,  0xEA,  0xBA,  0x00,  0x00,  0x16,  0x03,  0xF6,  0xC0,  0x00,  0x00,  0xF2,  0x68,  0x0A,
-  0x10,  0x44,  0x00,  0x4C,  0x00,  0x16
-};
-
-unsigned short _adv_mcode_size ASC_INITDATA =
-    sizeof(_adv_mcode_buf); /* 0x11D6 */
-unsigned long  _adv_mcode_chksum ASC_INITDATA = 0x03494981UL;
+/* a_mcode.h */
+STATIC unsigned char _adv_asc3550_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x01,  0xf6,
+  0x00,  0xf6,  0x18,  0xe4,  0x0a,  0x19,  0x18,  0x80,  0x02,  0x00,  0xff,  0xff,  0x03,  0xf6,  0x00,  0xfa,
+  0xff,  0x00,  0x82,  0xe7,  0x9e,  0xe7,  0x01,  0xfa,  0x06,  0x0e,  0x09,  0xe7,  0x00,  0xea,  0x01,  0xe6,
+  0x03,  0x00,  0x08,  0x00,  0x18,  0xf4,  0x55,  0xf0,  0x3e,  0x01,  0x3e,  0x57,  0x04,  0x00,  0x1e,  0xf0,
+  0x85,  0xf0,  0x00,  0xe6,  0x00,  0xec,  0x32,  0xf0,  0x86,  0xf0,  0xa4,  0x0c,  0xd0,  0x01,  0xd5,  0xf0,
+  0xf6,  0x18,  0x38,  0x54,  0x98,  0x57,  0xbc,  0x00,  0xb1,  0xf0,  0xb4,  0x00,  0x01,  0xfc,  0x02,  0x13,
+  0x03,  0xfc,  0x9e,  0x0c,  0x00,  0x57,  0x01,  0xf0,  0x03,  0xe6,  0x0c,  0x1c,  0x10,  0x00,  0x18,  0x40,
+  0x30,  0x12,  0x3e,  0x1c,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x48,  0x02,  0x80,  0x3c,  0x00,  0x4e,  0x01,
+  0x66,  0x15,  0x6c,  0x01,  0x6e,  0x01,  0xbb,  0x00,  0xda,  0x12,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,
+  0x08,  0x12,  0x30,  0xe4,  0x6a,  0x0f,  0xa8,  0x0c,  0xae,  0x0f,  0xb6,  0x00,  0xb9,  0x54,  0x00,  0x80,
+  0x04,  0x12,  0x06,  0xf7,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x3c,  0x56,  0x3e,  0x00,
+  0x4b,  0xe4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,
+  0x78,  0x01,  0x00,  0x01,  0x02,  0xee,  0x02,  0xfc,  0x03,  0x58,  0x03,  0xf7,  0x04,  0x80,  0x05,  0xfc,
+  0x08,  0x44,  0x09,  0xf0,  0x0a,  0x15,  0x10,  0x44,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,  0x40,  0x00,
+  0x4b,  0xf4,  0x4e,  0x1c,  0x5b,  0xf0,  0x5d,  0xf0,  0x80,  0x00,  0xaa,  0x00,  0xaa,  0x14,  0xb6,  0x08,
+  0xb8,  0x0f,  0xbb,  0x55,  0xbd,  0x56,  0xbe,  0x00,  0xc0,  0x00,  0x00,  0x4c,  0x00,  0xdc,  0x02,  0x4a,
+  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x08,  0x13,  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x0f,  0x00,
+  0x19,  0x00,  0x20,  0x00,  0x2a,  0x01,  0x32,  0x1c,  0x36,  0x00,  0x38,  0x12,  0x3c,  0x0b,  0x45,  0x5a,
+  0x56,  0x14,  0x59,  0xf0,  0x62,  0x0a,  0x69,  0x08,  0x83,  0x59,  0xae,  0x17,  0xb8,  0xf0,  0xba,  0x0f,
+  0xba,  0x17,  0xf0,  0x00,  0xf6,  0x0d,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,
+  0x04,  0xfc,  0x05,  0x00,  0x06,  0x00,  0x06,  0x12,  0x0a,  0x10,  0x0b,  0xf0,  0x0c,  0xf0,  0x12,  0x10,
+  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x38,  0x44,  0x40,  0x5c,  0x4a,  0xe4,  0x5a,  0x14,  0x62,  0x1a,
+  0x64,  0x0a,  0x68,  0x08,  0x68,  0x54,  0x83,  0x55,  0x83,  0x5a,  0x91,  0x44,  0x98,  0x12,  0x9a,  0x16,
+  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xce,  0x45,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,
+  0xec,  0x0d,  0x00,  0x54,  0x01,  0x48,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,  0x03,  0xa1,  0x04,  0x13,
+  0x05,  0xe6,  0x06,  0x0b,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0x12,  0x0a,  0xf0,
+  0x0c,  0x04,  0x0c,  0x10,  0x0c,  0x12,  0x0e,  0x13,  0x10,  0x10,  0x12,  0x1c,  0x17,  0x00,  0x18,  0x0e,
+  0x19,  0xe4,  0x1a,  0x10,  0x1c,  0x00,  0x1c,  0x12,  0x1c,  0x14,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,
+  0x20,  0xe7,  0x22,  0x01,  0x26,  0x01,  0x2a,  0x12,  0x30,  0xe7,  0x41,  0x58,  0x43,  0x48,  0x44,  0x55,
+  0x46,  0x1c,  0x4e,  0xe4,  0x5c,  0xf0,  0x72,  0x02,  0x74,  0x03,  0x77,  0x57,  0x88,  0x12,  0x89,  0x48,
+  0x92,  0x13,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0x9e,  0x00,  0xa8,  0x00,  0xaa,  0x12,  0xb9,  0x00,
+  0xba,  0x06,  0xbf,  0x57,  0xc0,  0x01,  0xc0,  0x08,  0xc2,  0x01,  0xfe,  0x9c,  0xf0,  0x26,  0x02,  0xfe,
+  0xc6,  0x0c,  0xff,  0x10,  0x00,  0x00,  0xfc,  0xfe,  0x18,  0x19,  0x00,  0xfa,  0xfe,  0x80,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0x2f,  0xfe,  0x01,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,  0xff,  0x09,  0x00,  0x00,
+  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,
+  0xff,  0x0f,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,
+  0xf7,  0xfa,  0x35,  0x51,  0x0c,  0x01,  0xfe,  0xb6,  0x0e,  0xfe,  0x04,  0xf7,  0xfa,  0x51,  0x0c,  0x1d,
+  0x35,  0xfe,  0x3d,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x20,  0xf0,  0xd0,  0x04,  0x55,  0x50,  0x02,  0xfe,
+  0xe2,  0x0c,  0x01,  0xfe,  0x42,  0x0d,  0xfe,  0xe9,  0x12,  0x02,  0xfe,  0x04,  0x03,  0xfe,  0x28,  0x1c,
+  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x4e,  0x13,  0xfe,  0xa6,  0x00,  0xc3,  0xfe,  0x48,  0xf0,
+  0xfe,  0x7c,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x96,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb4,  0x02,  0xfe,
+  0x46,  0xf0,  0xfe,  0x46,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x4c,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3a,
+  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x42,  0x02,  0x07,  0x0c,  0x9d,
+  0x07,  0x06,  0x13,  0xb8,  0x02,  0x26,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,
+  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0xfe,  0x0e,  0x17,  0xfe,  0xe7,  0x10,  0xfe,
+  0x06,  0xfc,  0xf5,  0x0e,  0x7b,  0x01,  0xc0,  0x02,  0x26,  0x17,  0x54,  0x47,  0xba,  0x01,  0xfe,  0x2c,
+  0x0f,  0x0e,  0x7b,  0x01,  0x9a,  0xfe,  0xbd,  0x10,  0x0e,  0x7b,  0x01,  0x9a,  0xfe,  0xad,  0x10,  0xfe,
+  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x07,  0x06,  0x13,  0xb8,  0x35,  0x1f,  0x26,  0xfe,  0x3d,  0xf0,  0xfe,
+  0xf8,  0x01,  0x27,  0xfe,  0x8a,  0x02,  0xfe,  0x5a,  0x1c,  0xd5,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,
+  0x00,  0x47,  0xba,  0x01,  0xfe,  0x1c,  0x0f,  0x07,  0x06,  0x13,  0xb8,  0x02,  0xfc,  0x22,  0x2b,  0x05,
+  0x10,  0x2f,  0xfe,  0x69,  0x10,  0x07,  0x06,  0x13,  0xb8,  0xfe,  0x04,  0xec,  0x2b,  0x08,  0x2b,  0x07,
+  0x3a,  0x1d,  0x01,  0x40,  0x7f,  0xfe,  0x05,  0xf6,  0xf5,  0x01,  0xfe,  0x40,  0x16,  0x0b,  0x49,  0x89,
+  0x37,  0x11,  0x43,  0x1d,  0xca,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x6a,  0x02,  0x26,  0x0e,  0x3b,  0x01,
+  0x14,  0x05,  0x10,  0xd3,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0xfe,  0x28,  0x10,  0x0e,  0xbd,  0x01,
+  0x14,  0xe5,  0x0e,  0x7c,  0x01,  0x14,  0xfe,  0x49,  0x54,  0x72,  0xfe,  0x12,  0x03,  0x08,  0x1c,  0x07,
+  0x3f,  0x01,  0x6a,  0x02,  0x26,  0x35,  0x7f,  0xfe,  0x02,  0xe8,  0x2d,  0xf9,  0xfe,  0x9e,  0x43,  0xed,
+  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xd0,  0xfe,  0x40,  0x1c,  0x1f,  0xec,  0xfe,  0x26,  0xf0,  0xfe,
+  0x70,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x5e,  0x03,  0xfe,  0x11,  0xf0,  0xd0,  0xfe,  0x0e,  0x10,  0xfe,
+  0x9f,  0xf0,  0xfe,  0x7e,  0x03,  0xe8,  0x12,  0xfe,  0x11,  0x00,  0x02,  0x4b,  0x35,  0xfe,  0x48,  0x1c,
+  0xe8,  0x1f,  0xec,  0x33,  0xec,  0xfe,  0x82,  0xf0,  0xfe,  0x84,  0x03,  0x29,  0x22,  0xbb,  0x68,  0x16,
+  0xbb,  0x0e,  0x7c,  0x01,  0x14,  0x68,  0x7d,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x40,  0x11,  0x3b,  0x08,
+  0x3b,  0x07,  0x99,  0x01,  0x6a,  0xf3,  0x11,  0xfe,  0xe4,  0x00,  0x2c,  0xfe,  0xca,  0x03,  0x1f,  0x31,
+  0x20,  0xfe,  0xda,  0x03,  0x01,  0x4a,  0xcb,  0xfe,  0xea,  0x03,  0x69,  0x8e,  0xcf,  0xfe,  0xaa,  0x06,
+  0x02,  0x25,  0x04,  0x7b,  0x2a,  0x1b,  0xfe,  0x1c,  0x05,  0x17,  0x84,  0x01,  0x38,  0x01,  0x95,  0x01,
+  0x98,  0x33,  0xfe,  0x5c,  0x02,  0x02,  0xeb,  0xe8,  0x35,  0x51,  0x18,  0xfe,  0x67,  0x1b,  0xf9,  0xed,
+  0xfe,  0x48,  0x1c,  0x8b,  0x01,  0xee,  0xa8,  0xfe,  0x96,  0xf0,  0xfe,  0x24,  0x04,  0x2c,  0xfe,  0x28,
+  0x04,  0x33,  0x26,  0x0e,  0x3b,  0x01,  0x14,  0x05,  0x10,  0x1b,  0xfe,  0x08,  0x05,  0x3c,  0x92,  0x9e,
+  0x2d,  0x81,  0x6d,  0x1f,  0x31,  0x20,  0x25,  0x04,  0x7b,  0x2a,  0xfe,  0x10,  0x12,  0x17,  0x84,  0x01,
+  0x38,  0x33,  0xfe,  0x5c,  0x02,  0x02,  0xeb,  0x30,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,
+  0x12,  0x0b,  0x09,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x28,  0x93,  0x01,  0x0a,  0x81,  0x6d,  0x20,  0xfe,
+  0xd8,  0x04,  0x23,  0x28,  0x93,  0x01,  0x0a,  0x20,  0x25,  0x23,  0x28,  0xb1,  0xfe,  0x4c,  0x44,  0xfe,
+  0x32,  0x12,  0x56,  0xfe,  0x44,  0x48,  0x08,  0xd6,  0xfe,  0x4c,  0x54,  0x72,  0xfe,  0x08,  0x05,  0x7f,
+  0x9e,  0x2d,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,  0x13,  0x3d,  0x05,  0xfe,  0xcc,  0x00,
+  0xfe,  0x40,  0x13,  0x0b,  0x09,  0x06,  0x8d,  0xfe,  0x06,  0x10,  0x23,  0x28,  0xb1,  0x0b,  0x09,  0x36,
+  0xdb,  0x17,  0xa2,  0x0b,  0x09,  0x06,  0x50,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x38,  0x33,  0xfe,  0x86,
+  0x0c,  0x02,  0x25,  0x39,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xac,  0x03,  0x17,  0xa2,  0x01,
+  0x38,  0x33,  0x26,  0x1f,  0x26,  0x02,  0xfe,  0x10,  0x05,  0xfe,  0x42,  0x5b,  0x51,  0x18,  0xfe,  0x46,
+  0x59,  0xf9,  0xed,  0x17,  0x74,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0b,  0x09,  0x0c,  0xfe,  0x78,
+  0x13,  0xfe,  0x20,  0x80,  0x05,  0x18,  0xfe,  0x70,  0x12,  0x6c,  0x09,  0x06,  0xfe,  0x60,  0x13,  0x04,
+  0xfe,  0xa2,  0x00,  0x2a,  0x1b,  0xfe,  0xa8,  0x05,  0xfe,  0x31,  0xe4,  0x6f,  0x6c,  0x09,  0x0c,  0xfe,
+  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x2a,  0xfe,  0x42,  0x12,  0x59,  0x2c,  0xfe,  0x68,  0x05,  0x1f,
+  0x31,  0xef,  0x01,  0x0a,  0x24,  0xfe,  0xc0,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x29,  0x6c,  0xfe,  0x4a,
+  0xf0,  0xfe,  0x92,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x8c,  0x05,  0xd1,  0x21,  0xfe,  0x21,  0x00,  0xa4,
+  0x21,  0xfe,  0x22,  0x00,  0x9d,  0x21,  0x89,  0xfe,  0x09,  0x48,  0x01,  0x0a,  0x24,  0xfe,  0xc0,  0x05,
+  0xfe,  0xe2,  0x08,  0x6c,  0x09,  0xda,  0x50,  0x01,  0xb6,  0x21,  0x06,  0x16,  0xe2,  0x47,  0xfe,  0x27,
+  0x01,  0x0b,  0x09,  0x36,  0xe3,  0x4e,  0x01,  0xae,  0x17,  0xa2,  0x0b,  0x09,  0x06,  0x50,  0x17,  0xfe,
+  0x0d,  0x00,  0x01,  0x38,  0x01,  0x95,  0x01,  0x98,  0x33,  0xfe,  0x86,  0x0c,  0x02,  0x25,  0x04,  0xfe,
+  0x9c,  0x00,  0x2a,  0xfe,  0x3e,  0x12,  0x04,  0x52,  0x2a,  0xfe,  0x36,  0x13,  0x4e,  0x01,  0xae,  0x24,
+  0xfe,  0x38,  0x06,  0x0e,  0x06,  0x6c,  0x09,  0x19,  0xfe,  0x02,  0x12,  0x79,  0x01,  0xfe,  0xf0,  0x13,
+  0x20,  0xfe,  0x2e,  0x06,  0x11,  0xbe,  0x01,  0x4a,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x52,  0xb9,  0x0f,
+  0x52,  0x04,  0xf4,  0x2a,  0xfe,  0x62,  0x12,  0x04,  0x4d,  0x2a,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x60,
+  0x18,  0x01,  0xfe,  0xb2,  0x18,  0xe6,  0xc8,  0x19,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,
+  0x1a,  0x4f,  0xc7,  0xc8,  0x87,  0x4e,  0x01,  0xae,  0x24,  0xfe,  0xa2,  0x06,  0x6c,  0x09,  0x1e,  0xa3,
+  0x7a,  0x0e,  0x54,  0x01,  0xfe,  0x1e,  0x14,  0x20,  0xfe,  0x98,  0x06,  0x11,  0xbe,  0x01,  0x4a,  0x11,
+  0xfe,  0xe5,  0x00,  0x04,  0x4d,  0xb9,  0x0f,  0x4d,  0x07,  0x06,  0x01,  0xae,  0xf3,  0x71,  0x8b,  0x01,
+  0xee,  0xa8,  0x11,  0xfe,  0xe2,  0x00,  0x2c,  0xf8,  0x1f,  0x31,  0xcf,  0xfe,  0xd6,  0x06,  0x80,  0xfe,
+  0x74,  0x07,  0xcb,  0xfe,  0x7c,  0x07,  0x69,  0x8e,  0x02,  0x25,  0x0b,  0x09,  0x0c,  0xfe,  0x2e,  0x12,
+  0x15,  0x18,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,
+  0xfe,  0x99,  0xa4,  0x01,  0x0a,  0x15,  0x00,  0x02,  0xfe,  0x3a,  0x08,  0x66,  0x09,  0x1e,  0x8d,  0x0b,
+  0x09,  0x1e,  0xfe,  0x30,  0x13,  0x15,  0xfe,  0x1b,  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,
+  0x00,  0x01,  0x0a,  0x15,  0x00,  0x01,  0x0a,  0x15,  0x06,  0x01,  0x0a,  0x15,  0x00,  0x02,  0xc9,  0x79,
+  0xfe,  0x9a,  0x81,  0x65,  0x89,  0xfe,  0x09,  0x6f,  0xfe,  0x93,  0x45,  0x1b,  0xfe,  0x84,  0x07,  0x2c,
+  0xfe,  0x5c,  0x07,  0x1f,  0x31,  0xcf,  0xfe,  0x54,  0x07,  0x69,  0x8e,  0x80,  0xfe,  0x74,  0x07,  0x02,
+  0x25,  0x01,  0x4a,  0x02,  0xf8,  0x15,  0x19,  0x02,  0xf8,  0xfe,  0x9c,  0xf7,  0xfe,  0xf0,  0x07,  0xfe,
+  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x73,  0xfe,  0xd2,  0x07,  0x0f,  0x5c,  0x13,  0x5d,  0x0b,  0x49,  0x6f,
+  0x37,  0x01,  0xfe,  0xf6,  0x17,  0x05,  0x10,  0x82,  0xfe,  0x83,  0xe7,  0x88,  0xa4,  0xfe,  0x03,  0x40,
+  0x0b,  0x49,  0x74,  0x37,  0x01,  0xb7,  0xab,  0xfe,  0x1f,  0x40,  0x16,  0x60,  0x01,  0xf6,  0xfe,  0x08,
+  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
+  0x0f,  0x5a,  0x13,  0x5b,  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,
+  0x0f,  0x41,  0x13,  0x42,  0xfe,  0x4a,  0x10,  0x0b,  0x09,  0x6f,  0xe3,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
+  0x90,  0x0f,  0x5c,  0x13,  0x5d,  0x0b,  0x09,  0x74,  0xc7,  0x01,  0xb7,  0xfe,  0x1f,  0x80,  0x16,  0x60,
+  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,  0x0f,  0x5e,  0x13,  0x5f,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,
+  0x0f,  0x5a,  0x13,  0x5b,  0xfe,  0x28,  0x90,  0xfe,  0xaa,  0x90,  0x0f,  0x41,  0x13,  0x42,  0x0f,  0x3e,
+  0x13,  0x57,  0x0b,  0x49,  0x19,  0x37,  0x35,  0x08,  0xa1,  0x2c,  0xfe,  0x50,  0x08,  0xfe,  0x9e,  0xf0,
+  0xfe,  0x64,  0x08,  0xc2,  0x1b,  0x31,  0x35,  0x6b,  0xfe,  0xed,  0x10,  0xa5,  0xfe,  0x88,  0x08,  0xa6,
+  0xfe,  0xa4,  0x08,  0x80,  0xfe,  0x7c,  0x08,  0xcb,  0xfe,  0x82,  0x08,  0x69,  0x8e,  0x02,  0x25,  0x01,
+  0x4a,  0xfe,  0xc9,  0x10,  0x15,  0x19,  0xfe,  0xc9,  0x10,  0x66,  0x09,  0x06,  0xfe,  0x10,  0x12,  0x66,
+  0x09,  0x0c,  0x48,  0x0b,  0x09,  0x0c,  0xfe,  0x66,  0x12,  0xfe,  0x2e,  0x1c,  0xa7,  0x66,  0x09,  0x06,
+  0x48,  0x66,  0x09,  0x0c,  0xfe,  0x52,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0x24,  0x09,
+  0xfe,  0xac,  0xf0,  0xfe,  0xc4,  0x08,  0xfe,  0x92,  0x10,  0xfe,  0x34,  0x1c,  0xfe,  0xf3,  0x10,  0xfe,
+  0xad,  0xf0,  0xfe,  0xd0,  0x08,  0x02,  0xfe,  0x32,  0x0a,  0xfe,  0x36,  0x1c,  0xfe,  0xe7,  0x10,  0xfe,
+  0x2b,  0xf0,  0xb0,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xfe,  0xdb,  0xc3,  0xfe,  0xd2,  0xf0,  0xb0,
+  0xfe,  0x76,  0x18,  0x1a,  0x18,  0x1b,  0xb0,  0x04,  0xe1,  0x1a,  0x06,  0x1b,  0xb0,  0xa5,  0x77,  0xa6,
+  0x77,  0xfe,  0x34,  0x1c,  0xfe,  0x36,  0x1c,  0xfe,  0xb1,  0x10,  0x8b,  0x59,  0x39,  0x17,  0xa2,  0x01,
+  0x38,  0x12,  0xfe,  0x35,  0x00,  0x33,  0x4b,  0x12,  0x8c,  0x02,  0x4b,  0xfe,  0x74,  0x18,  0x1a,  0xfe,
+  0x00,  0xf8,  0x1b,  0x77,  0x51,  0x1e,  0x01,  0xfe,  0x42,  0x0d,  0xd2,  0x08,  0x1c,  0x07,  0x3f,  0x01,
+  0x6a,  0x22,  0x2d,  0x3c,  0x51,  0x18,  0x02,  0x77,  0xfe,  0x98,  0x80,  0xd8,  0x0c,  0x27,  0xfe,  0x14,
+  0x0a,  0x0b,  0x09,  0x6f,  0xfe,  0x82,  0x12,  0x0b,  0x09,  0x19,  0xfe,  0x66,  0x13,  0x22,  0x60,  0x68,
+  0xc6,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,
+  0x62,  0x2d,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x73,  0xfb,  0x04,  0x5c,  0x2e,  0x5d,  0x0f,  0xaa,
+  0x13,  0x8c,  0x9b,  0x5c,  0x9c,  0x5d,  0x01,  0xb7,  0xab,  0x62,  0x2d,  0x16,  0x60,  0xa0,  0x3e,  0x67,
+  0x57,  0x63,  0x5e,  0x30,  0x5f,  0xe7,  0xfe,  0xe5,  0x55,  0xfe,  0x04,  0xfa,  0x3e,  0xfe,  0x05,  0xfa,
+  0x57,  0x01,  0xf6,  0xfe,  0x36,  0x10,  0x29,  0x0f,  0xaa,  0x0f,  0x8c,  0x63,  0x5e,  0x30,  0x5f,  0xa7,
+  0x0b,  0x09,  0x19,  0x1b,  0xfb,  0x63,  0x41,  0x30,  0x42,  0x0b,  0x09,  0xfe,  0xf7,  0x00,  0x37,  0x04,
+  0x5a,  0x2e,  0x5b,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,
+  0x77,  0x0b,  0x09,  0x19,  0x1b,  0xfb,  0x0b,  0x09,  0xfe,  0xf7,  0x00,  0x37,  0xfe,  0x3a,  0x55,  0xfe,
+  0x19,  0x81,  0x79,  0xfe,  0x10,  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x3d,  0x05,  0xbf,  0x1b,
+  0xfe,  0xcc,  0x08,  0x11,  0xbf,  0xfe,  0x98,  0x80,  0xd8,  0x0c,  0xfe,  0x14,  0x13,  0x04,  0x41,  0x2e,
+  0x42,  0x73,  0xfe,  0xcc,  0x08,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x77,  0x29,  0x4e,  0xfe,
+  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0b,  0x09,  0x0c,  0xa3,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,
+  0x94,  0x10,  0xfe,  0x6c,  0x19,  0x9b,  0x41,  0xfe,  0xed,  0x19,  0x9c,  0x42,  0xfe,  0x0c,  0x51,  0xfe,
+  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1a,  0xfe,  0x00,  0xff,  0x2f,  0xfe,  0x7a,  0x10,  0xc3,  0xfe,  0xd2,
+  0xf0,  0xfe,  0xac,  0x0a,  0xfe,  0x76,  0x18,  0x1a,  0x18,  0xce,  0x04,  0xe1,  0x1a,  0x06,  0x83,  0x12,
+  0xfe,  0x16,  0x00,  0x02,  0x4b,  0xfe,  0xd1,  0xf0,  0xfe,  0xe2,  0x0a,  0x17,  0xa1,  0x01,  0x38,  0x12,
+  0xd6,  0xfe,  0x48,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xca,  0x0a,  0x12,  0xfe,  0x21,  0x00,  0x02,  0x4b,
+  0xfe,  0xcd,  0xf0,  0xfe,  0xd6,  0x0a,  0x12,  0xfe,  0x22,  0x00,  0x02,  0x4b,  0xfe,  0xcb,  0xf0,  0xfe,
+  0xe2,  0x0a,  0x12,  0xfe,  0x24,  0x00,  0x02,  0x4b,  0xfe,  0xd0,  0xf0,  0xfe,  0xec,  0x0a,  0x12,  0x88,
+  0xd9,  0xfe,  0xcf,  0xf0,  0xfe,  0xf6,  0x0a,  0x12,  0x89,  0xd4,  0xfe,  0xcc,  0xf0,  0xc9,  0xfe,  0x84,
+  0x80,  0xd8,  0x19,  0xfe,  0xd5,  0x12,  0x12,  0xfe,  0x12,  0x00,  0x2c,  0xc9,  0x1f,  0x31,  0xa5,  0x25,
+  0xa6,  0x25,  0x35,  0xf3,  0x2c,  0xfe,  0x1a,  0x0b,  0x1f,  0x31,  0x80,  0xfe,  0x36,  0x0b,  0x69,  0x8e,
+  0xa5,  0xfe,  0xf0,  0x07,  0xa6,  0xfe,  0xf0,  0x07,  0x02,  0x25,  0x01,  0x4a,  0xfe,  0xdb,  0x10,  0x11,
+  0xfe,  0xe8,  0x00,  0x8b,  0x81,  0x6d,  0xfe,  0x89,  0xf0,  0x25,  0x23,  0x28,  0xfe,  0xe9,  0x09,  0x01,
+  0x0a,  0x81,  0x6d,  0x20,  0x25,  0x23,  0x28,  0x93,  0x33,  0xfe,  0x6e,  0x0b,  0x1f,  0x31,  0x02,  0xfe,
+  0x62,  0x0b,  0xc2,  0x48,  0x12,  0xfe,  0x42,  0x00,  0x02,  0x4b,  0x9f,  0x06,  0xfe,  0x81,  0x49,  0xfe,
+  0xcc,  0x12,  0x0b,  0x09,  0x0c,  0xfe,  0x5a,  0x13,  0x12,  0x00,  0x58,  0x0c,  0xfe,  0x6a,  0x12,  0x58,
+  0xfe,  0x28,  0x00,  0x27,  0xfe,  0xb4,  0x0c,  0x0e,  0x7c,  0x01,  0x14,  0x05,  0x00,  0x83,  0x34,  0xfe,
+  0x28,  0x00,  0x02,  0xfe,  0xb4,  0x0c,  0x01,  0x95,  0x01,  0x98,  0x0e,  0xbd,  0x01,  0xfe,  0x10,  0x0e,
+  0xaf,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0x02,
+  0x26,  0x12,  0xfe,  0x44,  0x00,  0x58,  0x0c,  0xa3,  0x34,  0x0c,  0xfe,  0xc0,  0x10,  0x01,  0xb6,  0x34,
+  0x0c,  0xfe,  0xb6,  0x10,  0x01,  0xb6,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x34,
+  0x0c,  0x12,  0xfe,  0x43,  0x00,  0xfe,  0xa2,  0x10,  0x0b,  0x49,  0x0c,  0x37,  0x01,  0x95,  0x01,  0x98,
+  0xaf,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,  0x07,  0x3f,  0x01,  0x76,  0x51,
+  0x0c,  0xaf,  0x1d,  0xca,  0x02,  0xfe,  0x48,  0x03,  0x0b,  0x09,  0x0c,  0xce,  0x34,  0x0c,  0x12,  0x00,
+  0xfe,  0x54,  0x10,  0x66,  0x09,  0x1e,  0xfe,  0x50,  0x12,  0x0b,  0x09,  0x1e,  0xfe,  0x48,  0x13,  0xfe,
+  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x72,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x78,
+  0x0c,  0x0b,  0x49,  0x1e,  0x37,  0xfe,  0x95,  0x10,  0x12,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0c,
+  0x79,  0xfe,  0x26,  0x10,  0x12,  0xfe,  0x13,  0x00,  0xd4,  0x12,  0xfe,  0x47,  0x00,  0xa4,  0x12,  0xfe,
+  0x41,  0x00,  0x9d,  0x12,  0xfe,  0x24,  0x00,  0x04,  0x7b,  0x2a,  0x27,  0xeb,  0x79,  0xfe,  0x04,  0xe6,
+  0x1e,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0xaf,  0x01,  0xd7,  0x02,  0x26,  0xd5,  0x17,  0x0c,  0x47,
+  0xf2,  0xdf,  0x17,  0xfe,  0x31,  0x00,  0x47,  0xba,  0x01,  0xfe,  0x1c,  0x0f,  0x02,  0xfc,  0x1d,  0xfe,
+  0x06,  0xec,  0xf7,  0x85,  0x34,  0x36,  0xbc,  0x2f,  0x1d,  0xfe,  0x06,  0xea,  0xf7,  0xfe,  0x47,  0x4b,
+  0x7a,  0xfe,  0x75,  0x57,  0x04,  0x55,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0e,  0x7c,  0xfe,  0xfa,
+  0x14,  0x4e,  0xe5,  0x0e,  0xbd,  0xfe,  0xf0,  0x14,  0xfe,  0x49,  0x54,  0x91,  0xfe,  0x28,  0x0d,  0x0e,
+  0x1c,  0xfe,  0xe4,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x48,  0x03,  0x0e,  0x55,  0xfe,  0xc8,  0x14,
+  0x85,  0x34,  0x36,  0xbc,  0x2f,  0x1d,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x26,  0x22,  0x2b,
+  0x05,  0x10,  0xfe,  0x78,  0x12,  0x29,  0x16,  0x54,  0x16,  0xa9,  0x22,  0x43,  0x4e,  0x47,  0x43,  0xc2,
+  0xfe,  0x0c,  0x13,  0xfe,  0xbc,  0xf0,  0xfe,  0xc4,  0x0d,  0x08,  0x06,  0x16,  0x54,  0x01,  0xfe,  0xd0,
+  0x15,  0x04,  0xfe,  0x38,  0x01,  0x2e,  0xfe,  0x3a,  0x01,  0x73,  0xfe,  0xc8,  0x0d,  0x04,  0xfe,  0x38,
+  0x01,  0x1a,  0xfe,  0xf0,  0xff,  0x0f,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0f,  0xfe,  0x62,
+  0x01,  0x21,  0x06,  0x16,  0x43,  0xfe,  0x04,  0xec,  0x2b,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x01,  0x40,
+  0x7f,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x40,  0x16,  0x11,  0x43,  0xca,  0x08,  0x06,
+  0x03,  0x29,  0x03,  0x22,  0x54,  0xfe,  0xf7,  0x12,  0x22,  0xa9,  0x68,  0x16,  0xa9,  0x05,  0xa1,  0xfe,
+  0x93,  0x13,  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x47,  0xf2,  0xdf,  0xfe,  0xd9,  0x10,  0x94,  0xfe,  0x03,
+  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x94,  0xfe,  0x03,  0xdc,  0x29,  0xfe,  0x70,  0x57,
+  0xfe,  0x33,  0x54,  0xfe,  0x3b,  0x54,  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x94,  0x29,  0xfe,
+  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0x94,  0x7d,  0x03,  0x01,  0xfe,  0x70,  0x16,  0x3d,  0x05,  0x43,
+  0xfe,  0x0a,  0x13,  0x08,  0x1c,  0x07,  0x3f,  0xd4,  0x01,  0x95,  0x01,  0x98,  0x08,  0x3b,  0x07,  0x99,
+  0x01,  0x40,  0x11,  0xfe,  0xe9,  0x00,  0x0b,  0x09,  0x89,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0x02,  0x16,
+  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0x0f,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0f,  0xfe,  0x66,
+  0x01,  0x0b,  0x09,  0x74,  0x8d,  0xfe,  0x03,  0x80,  0x6b,  0x3c,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,
+  0x1d,  0x92,  0x01,  0x6a,  0xfe,  0x62,  0x08,  0x68,  0x3c,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,  0x1d,
+  0x92,  0x01,  0x6a,  0x62,  0x2d,  0x11,  0x75,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x92,  0x01,  0x76,  0x03,
+  0xfe,  0x08,  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,
+  0x58,  0x04,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,
+  0x0a,  0x1c,  0x21,  0x87,  0x16,  0xf7,  0x29,  0x0f,  0x52,  0x0f,  0x4d,  0x21,  0x10,  0x16,  0x2b,  0x16,
+  0x3a,  0x56,  0x9f,  0xd6,  0x08,  0x2b,  0x07,  0x3a,  0x1d,  0x01,  0x76,  0x7f,  0x11,  0x75,  0xfe,  0x14,
+  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xf6,  0x0e,  0xd5,  0x8b,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,
+  0x18,  0x1c,  0x03,  0x1d,  0xfe,  0x0c,  0x14,  0x85,  0xfe,  0x07,  0xe6,  0x36,  0xfe,  0xce,  0x47,  0xfe,
+  0xf5,  0x13,  0x03,  0x01,  0xb6,  0x0e,  0x3b,  0x01,  0x14,  0x05,  0x10,  0xd3,  0x0e,  0x1c,  0x01,  0x14,
+  0x05,  0x10,  0xdb,  0xfe,  0x44,  0x58,  0x3c,  0xfe,  0x01,  0xec,  0xba,  0xfe,  0x9e,  0x40,  0xfe,  0x9d,
+  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1e,  0x9e,  0x2d,  0x01,  0xd7,  0xfe,  0xc9,  0x10,  0x03,  0x35,  0x81,
+  0x6d,  0x23,  0x28,  0xb1,  0x05,  0x1e,  0xfe,  0x48,  0x12,  0x05,  0x0c,  0xfe,  0x4c,  0x12,  0x05,  0x18,
+  0x38,  0x05,  0xcc,  0x1b,  0xfe,  0xc0,  0x10,  0x05,  0xfe,  0x23,  0x00,  0x1b,  0xfe,  0xcc,  0x10,  0x05,
+  0x06,  0x1b,  0xfe,  0x2a,  0x11,  0x05,  0x19,  0xfe,  0x12,  0x12,  0x05,  0x00,  0x1b,  0x25,  0x17,  0xcc,
+  0x01,  0x38,  0xc4,  0x39,  0x01,  0x0a,  0x80,  0x4a,  0x03,  0x39,  0x11,  0xfe,  0xcc,  0x00,  0x02,  0x26,
+  0x39,  0x3d,  0x05,  0xbf,  0xfe,  0xe3,  0x13,  0x63,  0x41,  0x30,  0x42,  0x73,  0xfe,  0x7e,  0x10,  0x0b,
+  0x09,  0x6f,  0xfe,  0x72,  0x12,  0xa0,  0x3e,  0x67,  0x57,  0xe7,  0xfe,  0xe5,  0x55,  0x91,  0xfe,  0x48,
+  0x10,  0x22,  0x60,  0xfe,  0x26,  0x13,  0x04,  0xaa,  0x2e,  0x8c,  0x73,  0xfe,  0x98,  0x0c,  0x0f,  0x5c,
+  0x13,  0x5d,  0x29,  0x0f,  0xaa,  0x0f,  0x8c,  0x01,  0xb7,  0x21,  0x87,  0x6b,  0x16,  0x60,  0x01,  0xf6,
+  0xa0,  0x3e,  0x67,  0x57,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x3e,  0xfe,  0x05,
+  0xfa,  0x57,  0xfe,  0x91,  0x10,  0x04,  0x5e,  0x2e,  0x5f,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0f,
+  0x5e,  0x13,  0x5f,  0xd1,  0xa0,  0x3e,  0x67,  0x57,  0xe7,  0xfe,  0xe5,  0x55,  0x04,  0x5a,  0x2e,  0x5b,
+  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0f,  0x5a,  0x13,  0x5b,  0x0b,  0x09,  0x6f,  0xfe,  0x1e,  0x12,
+  0x22,  0x60,  0xfe,  0x1f,  0x40,  0x04,  0x5c,  0x2e,  0x5d,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,
+  0x5e,  0x2e,  0x5f,  0xfe,  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x5a,  0x2e,  0x5b,  0xfe,  0x08,  0x50,
+  0xfe,  0x8a,  0x50,  0x04,  0x41,  0x2e,  0x42,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x97,  0x21,
+  0x06,  0x16,  0xf1,  0x02,  0x78,  0x39,  0x01,  0x0a,  0x20,  0x4c,  0x23,  0x28,  0xb1,  0x05,  0x06,  0x27,
+  0x4c,  0x3d,  0x05,  0xbf,  0x27,  0x78,  0x01,  0xee,  0x1a,  0x4f,  0x1b,  0x4c,  0x0b,  0x09,  0x0c,  0xde,
+  0x63,  0x41,  0x30,  0x42,  0xfe,  0x0a,  0x55,  0x2f,  0xfe,  0x8b,  0x55,  0x9b,  0x41,  0x9c,  0x42,  0xfe,
+  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x78,  0xfe,  0x19,  0x81,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,
+  0x02,  0x78,  0x39,  0x01,  0x0a,  0x20,  0xfe,  0xc2,  0x0f,  0x23,  0x28,  0xfe,  0xe9,  0x09,  0x58,  0x18,
+  0xfe,  0x94,  0x12,  0x58,  0x0c,  0x50,  0x02,  0x4c,  0x2c,  0xfe,  0x4a,  0x11,  0x1f,  0x31,  0x20,  0xfe,
+  0xc2,  0x0f,  0x23,  0x28,  0x93,  0x05,  0x18,  0x27,  0x4c,  0x01,  0x0a,  0x20,  0xfe,  0xc2,  0x0f,  0x23,
+  0x28,  0xfe,  0xe8,  0x09,  0x56,  0x04,  0xfe,  0x9c,  0x00,  0x2a,  0x2f,  0xfe,  0xbb,  0x45,  0x58,  0x00,
+  0x48,  0x34,  0x06,  0x9f,  0x4f,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,  0x14,  0xa8,  0x3d,  0x05,  0xbe,  0xfe,
+  0x16,  0x13,  0x04,  0xf4,  0x2a,  0xce,  0x04,  0x4d,  0x2a,  0x2f,  0x59,  0x02,  0x78,  0xfe,  0xc0,  0x5d,
+  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,  0x04,  0x52,  0xb9,  0x0f,  0x52,  0x59,  0x39,  0x01,  0x0a,  0x24,
+  0x97,  0x01,  0xfe,  0xf0,  0x13,  0x02,  0x97,  0x2c,  0xfe,  0xd4,  0x11,  0x1f,  0x31,  0x20,  0x4c,  0x23,
+  0x28,  0x93,  0x05,  0x06,  0x27,  0x4c,  0xfe,  0xf6,  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,
+  0x92,  0x14,  0xa8,  0xfe,  0x4a,  0xf4,  0x0c,  0x1b,  0x4c,  0xfe,  0x4a,  0xf4,  0x06,  0xd2,  0x3d,  0x05,
+  0xbe,  0xc7,  0x02,  0x78,  0x04,  0x4d,  0xb9,  0x0f,  0x4d,  0x59,  0x39,  0x01,  0x0a,  0x24,  0x97,  0x01,
+  0xfe,  0x1e,  0x14,  0x02,  0x97,  0x24,  0xfe,  0x3c,  0x12,  0x71,  0xef,  0x71,  0x03,  0x33,  0x8d,  0x69,
+  0x8d,  0x59,  0x39,  0x01,  0x0a,  0xfe,  0xe3,  0x10,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,
+  0x1a,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x61,  0xff,  0x02,  0x00,
+  0x57,  0x64,  0x7e,  0x1a,  0x4f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x08,  0x61,  0xff,  0x02,
+  0x00,  0x57,  0x64,  0x7e,  0x03,  0x08,  0x61,  0xff,  0x02,  0x00,  0x57,  0x64,  0x7e,  0xfe,  0x0b,  0x58,
+  0x03,  0x0e,  0x52,  0x01,  0x9a,  0x0e,  0x4d,  0x01,  0x9a,  0x03,  0xc6,  0x1a,  0x10,  0xff,  0x03,  0x00,
+  0x54,  0xfe,  0x00,  0xf4,  0x19,  0x64,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,
+  0x03,  0x7c,  0x62,  0x2d,  0x0f,  0x5a,  0x13,  0x5b,  0x9b,  0x5e,  0x9c,  0x5f,  0x03,  0xfe,  0x62,  0x18,
+  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,  0xb4,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x60,  0x18,  0xfe,
+  0x42,  0x48,  0x79,  0x56,  0x7a,  0x01,  0x0a,  0x20,  0xfe,  0xe8,  0x13,  0x23,  0x28,  0xfe,  0xe9,  0x09,
+  0xfe,  0xc1,  0x59,  0x01,  0x0a,  0x20,  0xfe,  0xe8,  0x13,  0x23,  0x28,  0xfe,  0xe8,  0x0a,  0x04,  0xf4,
+  0x2a,  0xfe,  0xc2,  0x12,  0x29,  0xad,  0x1e,  0xde,  0x58,  0xcd,  0x72,  0xfe,  0x38,  0x13,  0x50,  0x08,
+  0x06,  0x07,  0xcd,  0x9f,  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa4,  0xff,
+  0x02,  0x83,  0x55,  0xad,  0x18,  0xfe,  0x12,  0x13,  0x70,  0xfe,  0x30,  0x00,  0x91,  0xf0,  0x07,  0x84,
+  0x08,  0x06,  0xfe,  0x56,  0x10,  0xad,  0x0c,  0xfe,  0x16,  0x13,  0x70,  0xfe,  0x64,  0x00,  0x91,  0xf0,
+  0x0e,  0xfe,  0x64,  0x00,  0x07,  0x88,  0x08,  0x06,  0xfe,  0x28,  0x10,  0xad,  0x06,  0xfe,  0x5e,  0x13,
+  0x70,  0xfe,  0xc8,  0x00,  0x91,  0xf0,  0x0e,  0xfe,  0xc8,  0x00,  0x07,  0x54,  0x08,  0x06,  0xd1,  0x70,
+  0xfe,  0x90,  0x01,  0xea,  0xfe,  0x9e,  0x13,  0x7a,  0xa7,  0xfe,  0x43,  0xf4,  0xa9,  0xfe,  0x56,  0xf0,
+  0xfe,  0xb0,  0x13,  0xfe,  0x04,  0xf4,  0x61,  0xfe,  0x43,  0xf4,  0x88,  0xfe,  0xf3,  0x10,  0xac,  0x01,
+  0xfe,  0x7a,  0x12,  0x1a,  0x4f,  0xd3,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x87,  0xea,  0xfe,  0xe2,
+  0x13,  0x7a,  0xfe,  0x14,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x19,  0xea,  0xfe,  0xe2,  0x13,
+  0xc8,  0x19,  0x9d,  0x56,  0x7a,  0x08,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x56,  0x08,
+  0x0c,  0x03,  0x15,  0x06,  0x01,  0x0a,  0x24,  0xdc,  0x15,  0x0c,  0x01,  0x0a,  0x24,  0xdc,  0x15,  0x18,
+  0x01,  0x0a,  0x24,  0xdc,  0x71,  0xfe,  0x89,  0x49,  0x01,  0x0a,  0x03,  0x15,  0x06,  0x01,  0x0a,  0x24,
+  0x90,  0x15,  0x18,  0x01,  0x0a,  0x24,  0x90,  0x15,  0x06,  0x01,  0x0a,  0x24,  0x90,  0xfe,  0x89,  0x49,
+  0x01,  0x0a,  0x24,  0x90,  0x71,  0xfe,  0x89,  0x4a,  0x01,  0x0a,  0x03,  0x56,  0x03,  0x22,  0xe2,  0x05,
+  0x06,  0xfe,  0x44,  0x13,  0xab,  0x16,  0xe2,  0xfe,  0x49,  0xf4,  0x00,  0x50,  0x71,  0xc4,  0x59,  0xfe,
+  0x01,  0xec,  0xfe,  0x27,  0x01,  0xef,  0x01,  0x0a,  0x3d,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,
+  0x20,  0xfe,  0xa0,  0x14,  0x29,  0x16,  0xf1,  0x01,  0x4a,  0x22,  0xf1,  0x05,  0x06,  0x48,  0x0b,  0x49,
+  0x06,  0x37,  0x03,  0x0f,  0x53,  0x13,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x14,  0x05,  0x10,  0xfe,  0x1e,
+  0x12,  0x45,  0xe6,  0x8f,  0x01,  0x44,  0xfe,  0x90,  0x4d,  0xe0,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x44,
+  0xfe,  0x8d,  0x56,  0xb4,  0x45,  0x03,  0x45,  0x30,  0x8a,  0x01,  0x14,  0x45,  0x8f,  0x01,  0x44,  0xe4,
+  0x10,  0xe0,  0x10,  0x30,  0x53,  0x70,  0x1c,  0x83,  0x0e,  0x55,  0x01,  0xc0,  0x03,  0x0f,  0x53,  0x13,
+  0x8a,  0xfe,  0xc3,  0x58,  0x01,  0x14,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x45,  0xe6,  0x8f,  0x01,  0x44,
+  0xe4,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x44,  0x45,  0x03,  0x45,  0x30,  0x53,  0x01,
+  0x14,  0x45,  0x8f,  0x01,  0x44,  0xe4,  0x10,  0xe0,  0x10,  0x30,  0x53,  0x70,  0x1c,  0x83,  0x0e,  0x55,
+  0x01,  0xc0,  0x03,  0x0f,  0x53,  0x13,  0x8a,  0xfe,  0x43,  0x58,  0x01,  0x14,  0xfe,  0x42,  0x48,  0x8f,
+  0x01,  0x44,  0xfe,  0xc0,  0x5a,  0xac,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xde,
+  0x94,  0x7d,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x67,  0x53,  0xfe,  0x4d,  0xf4,  0x1c,  0xfe,  0x1c,  0x13,
+  0x0e,  0x55,  0x01,  0x9a,  0xa7,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x44,  0xfe,  0x00,  0x07,
+  0x7d,  0x05,  0x10,  0x83,  0x67,  0x8a,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,
+  0x44,  0xfe,  0x8d,  0x56,  0xb4,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x07,  0x10,  0x6e,  0x65,
+  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xdd,  0x36,  0x96,  0xfe,
+  0xe4,  0x15,  0x01,  0xfe,  0xea,  0x16,  0xfe,  0x0c,  0x13,  0x86,  0x36,  0x65,  0xfe,  0x2c,  0x01,  0xfe,
+  0x2f,  0x19,  0x03,  0xb5,  0x27,  0xfe,  0xd4,  0x15,  0xfe,  0xda,  0x10,  0x07,  0x10,  0x6e,  0x04,  0xfe,
+  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x19,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,
+  0x86,  0x19,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x65,  0xfe,  0x38,  0x00,
+  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x19,  0x96,  0xfe,  0x2e,  0x16,  0xfe,  0xb6,  0x14,  0x2f,  0x03,
+  0xb5,  0x27,  0xfe,  0x06,  0x16,  0xfe,  0x9c,  0x10,  0x07,  0x10,  0x6e,  0xb4,  0xfe,  0x18,  0xdf,  0xfe,
+  0x19,  0xdf,  0xdd,  0x3e,  0x96,  0xfe,  0x50,  0x16,  0xfe,  0x94,  0x14,  0xfe,  0x10,  0x13,  0x86,  0x3e,
+  0x65,  0x1e,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,  0x03,  0xb5,  0x27,  0xfe,  0x44,  0x16,  0xfe,
+  0x6c,  0x10,  0x07,  0x10,  0x6e,  0xfe,  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x86,  0xda,  0x65,  0x1e,  0xfe,
+  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xda,  0x96,  0xfe,  0x88,  0x16,  0xfe,  0x5c,  0x14,  0x2f,  0x03,  0xb5,
+  0x27,  0xfe,  0x74,  0x16,  0xfe,  0x42,  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x6e,  0xfe,  0x18,  0xfe,  0x5c,
+  0xfe,  0x19,  0xfe,  0x5d,  0xc6,  0xdd,  0x74,  0x96,  0xfe,  0xae,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,
+  0x13,  0x86,  0x74,  0x4e,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,
+  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x62,  0x2d,  0x03,  0x62,  0x2d,  0xfe,  0x12,  0x45,  0x27,  0xfe,
+  0x9e,  0x16,  0x17,  0x06,  0x47,  0xf2,  0xdf,  0x02,  0x26,  0xfe,  0x39,  0xf0,  0xfe,  0xf2,  0x16,  0x29,
+  0x03,  0xfe,  0x7e,  0x18,  0x1a,  0x18,  0x82,  0x08,  0x0d,  0x03,  0x6e,  0x04,  0xe1,  0x1a,  0x06,  0xfe,
+  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1d,  0x0e,  0x1c,  0x01,  0x14,  0x05,  0x10,  0x48,  0x3c,  0xfe,  0x78,
+  0x14,  0xfe,  0x34,  0x12,  0x4f,  0x85,  0x34,  0x36,  0xbc,  0xfe,  0xe9,  0x13,  0x1d,  0x0e,  0x3b,  0x01,
+  0x14,  0x05,  0x10,  0x48,  0x3c,  0x90,  0xe3,  0x4f,  0x85,  0x34,  0x36,  0xbc,  0xfe,  0xe9,  0x13,  0x07,
+  0x0c,  0x03,  0xfe,  0x9c,  0xe7,  0x0c,  0x12,  0xfe,  0x15,  0x00,  0x92,  0x9e,  0x2d,  0x01,  0xd7,  0x07,
+  0x06,  0x03,  0x0b,  0x49,  0x36,  0x37,  0x08,  0x3b,  0x07,  0x99,  0x01,  0x40,  0x11,  0x43,  0x08,  0x1c,
+  0x07,  0x3f,  0x01,  0x76,  0x07,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x63,  0xf5,  0x30,
+  0x75,  0xfe,  0x48,  0x55,  0x2f,  0xfe,  0xc9,  0x55,  0x03,  0x22,  0xbb,  0x6b,  0x16,  0xbb,  0x03,  0x0e,
+  0xbd,  0x01,  0x14,  0xe5,  0x0e,  0x7c,  0x01,  0x14,  0xfe,  0x49,  0x44,  0x27,  0xfe,  0xe8,  0x17,  0x0e,
+  0x1c,  0x01,  0x14,  0x05,  0x10,  0x48,  0x0e,  0x55,  0x01,  0xc0,  0x0e,  0x7c,  0x01,  0x14,  0x6b,  0x7d,
+  0x03,  0xfe,  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x22,  0x3a,  0x05,  0x10,  0xfe,  0x52,
+  0x12,  0x3c,  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,
+  0xfe,  0x10,  0x13,  0xfe,  0xe2,  0x08,  0x6b,  0x3c,  0x3d,  0x05,  0x75,  0xa3,  0xfe,  0x82,  0x48,  0xfe,
+  0x01,  0x80,  0xfe,  0xd7,  0x10,  0xfe,  0xc4,  0x48,  0x08,  0x2b,  0x07,  0x3a,  0xfe,  0x40,  0x5f,  0x1d,
+  0x01,  0x40,  0x11,  0xfe,  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x08,  0x2b,  0x07,  0x3a,  0x01,  0x40,  0x11,
+  0xfe,  0xdd,  0x00,  0xfe,  0x40,  0x4a,  0x68,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,
+  0xfe,  0x04,  0x17,  0x03,  0xe9,  0x18,  0x72,  0xfe,  0x70,  0x18,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,
+  0x45,  0xfe,  0x2c,  0x10,  0xe9,  0xcc,  0x72,  0xfe,  0x82,  0x18,  0x04,  0xfe,  0x92,  0x00,  0xc5,  0x1e,
+  0xd9,  0xe9,  0xfe,  0x0b,  0x00,  0x72,  0xfe,  0x94,  0x18,  0x04,  0xfe,  0x94,  0x00,  0xc5,  0x19,  0xfe,
+  0x08,  0x10,  0x04,  0xfe,  0x96,  0x00,  0xc5,  0x84,  0xfe,  0x4e,  0x45,  0xd2,  0xfe,  0x0a,  0x45,  0xff,
+  0x04,  0x68,  0x54,  0xfe,  0xf1,  0x10,  0x1a,  0x87,  0x03,  0x05,  0xa1,  0xfe,  0x5a,  0xf0,  0xfe,  0xc0,
+  0x18,  0x21,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1e,  0xfe,  0x5a,  0xf0,  0xfe,  0xce,  0x18,
+  0x21,  0xcd,  0xfe,  0x26,  0x10,  0x05,  0x18,  0x82,  0x21,  0x84,  0xd9,  0x05,  0x0c,  0x82,  0x21,  0x88,
+  0xfe,  0x0e,  0x10,  0x05,  0x06,  0x82,  0x21,  0x54,  0xc4,  0xab,  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,
+  0x38,  0x2c,  0xfe,  0xfe,  0x18,  0x04,  0x6d,  0xac,  0x03,  0x1f,  0xfe,  0x16,  0x19,  0xfe,  0x14,  0xf0,
+  0x0a,  0x2c,  0xfe,  0x12,  0x19,  0x03,  0xff,  0x34,  0x00,  0x00,};
+
+STATIC unsigned short _adv_asc3550_size =
+    sizeof(_adv_asc3550_buf); /* 0x13AA */
+STATIC unsigned long _adv_asc3550_chksum =
+    0x04F4788EUL; /* Expanded checksum. */
+
+STATIC unsigned char _adv_asc38C0800_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x00,  0xfc,  0x48,  0xe4,  0x01,  0x00,  0x00,  0xf6,
+  0x18,  0xe4,  0x01,  0xf6,  0x18,  0x80,  0x02,  0x00,  0x02,  0x1a,  0xff,  0xff,  0x00,  0xfa,  0x03,  0xf6,
+  0xff,  0x00,  0x82,  0xe7,  0x01,  0xfa,  0x9e,  0xe7,  0x09,  0xe7,  0xe6,  0x0e,  0x00,  0xea,  0x01,  0xe6,
+  0x03,  0x00,  0x1e,  0xf0,  0x55,  0xf0,  0x18,  0xf4,  0x3e,  0x57,  0x04,  0x00,  0x3e,  0x01,  0x85,  0xf0,
+  0x00,  0xe6,  0x03,  0xfc,  0x08,  0x00,  0x32,  0xf0,  0x38,  0x54,  0x84,  0x0d,  0x86,  0xf0,  0xd4,  0x01,
+  0xd5,  0xf0,  0xee,  0x19,  0x00,  0xec,  0x01,  0xfc,  0x98,  0x57,  0xbc,  0x00,  0x10,  0x13,  0xb1,  0xf0,
+  0x02,  0x13,  0x3c,  0x00,  0x7e,  0x0d,  0xb4,  0x00,  0x00,  0x57,  0x01,  0xf0,  0x02,  0xfc,  0x03,  0xe6,
+  0x0c,  0x1c,  0x10,  0x00,  0x18,  0x40,  0x3e,  0x1c,  0xbd,  0x00,  0xe0,  0x00,  0x02,  0x80,  0x3e,  0x00,
+  0x46,  0x16,  0x4a,  0x10,  0x6c,  0x01,  0x6e,  0x01,  0x74,  0x01,  0x76,  0x01,  0xb9,  0x54,  0xba,  0x13,
+  0xbb,  0x00,  0x00,  0x4e,  0x01,  0x01,  0x01,  0xea,  0x02,  0x48,  0x02,  0xfa,  0x08,  0x12,  0x30,  0xe4,
+  0x3c,  0x56,  0x4e,  0x01,  0x5d,  0xf0,  0x7a,  0x01,  0x88,  0x0d,  0x8e,  0x10,  0xb6,  0x00,  0xc4,  0x08,
+  0x00,  0x80,  0x04,  0x12,  0x05,  0xfc,  0x24,  0x01,  0x28,  0x01,  0x32,  0x00,  0x3c,  0x01,  0x40,  0x00,
+  0x4b,  0xe4,  0x4b,  0xf4,  0x4c,  0x1c,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x78,  0x01,
+  0x7c,  0x01,  0xbb,  0x55,  0x00,  0x01,  0x02,  0xee,  0x03,  0x58,  0x03,  0xf7,  0x03,  0xfa,  0x04,  0x80,
+  0x08,  0x44,  0x09,  0xf0,  0x10,  0x44,  0x1b,  0x80,  0x20,  0x01,  0x38,  0x1c,  0x4e,  0x1c,  0x5b,  0xf0,
+  0x80,  0x00,  0x8a,  0x15,  0x98,  0x10,  0xaa,  0x00,  0xbd,  0x56,  0xbe,  0x00,  0xc0,  0x00,  0x00,  0x4c,
+  0x00,  0xdc,  0x02,  0x4a,  0x04,  0xfc,  0x05,  0xf0,  0x05,  0xf8,  0x06,  0x13,  0x06,  0xf7,  0x08,  0x13,
+  0x0c,  0x00,  0x0e,  0x47,  0x0e,  0xf7,  0x0f,  0x00,  0x1c,  0x0c,  0x20,  0x00,  0x2a,  0x01,  0x32,  0x1c,
+  0x36,  0x00,  0x42,  0x54,  0x44,  0x0b,  0x44,  0x55,  0x45,  0x5a,  0x59,  0xf0,  0x5c,  0xf0,  0x62,  0x0a,
+  0x69,  0x08,  0x78,  0x13,  0x83,  0x59,  0x8e,  0x18,  0x9a,  0x10,  0x9a,  0x18,  0xb8,  0xf0,  0xd6,  0x0e,
+  0xea,  0x15,  0xf0,  0x00,  0x04,  0x10,  0x04,  0xea,  0x04,  0xf6,  0x05,  0x00,  0x06,  0x00,  0x06,  0x12,
+  0x0a,  0x10,  0x0a,  0x12,  0x0b,  0xf0,  0x0c,  0x10,  0x0c,  0xf0,  0x12,  0x10,  0x19,  0x00,  0x19,  0xe4,
+  0x2a,  0x12,  0x30,  0x1c,  0x33,  0x00,  0x34,  0x00,  0x36,  0x15,  0x38,  0x44,  0x3a,  0x15,  0x40,  0x5c,
+  0x4a,  0xe4,  0x62,  0x1a,  0x68,  0x08,  0x68,  0x54,  0x7a,  0x17,  0x83,  0x55,  0x83,  0x5a,  0x91,  0x44,
+  0xa2,  0x10,  0xa4,  0x00,  0xb0,  0x57,  0xb5,  0x00,  0xba,  0x00,  0xcc,  0x0e,  0xce,  0x45,  0xd0,  0x00,
+  0xe1,  0x00,  0xe5,  0x55,  0xe7,  0x00,  0x00,  0x54,  0x01,  0x48,  0x01,  0x58,  0x02,  0x10,  0x02,  0xe6,
+  0x03,  0xa1,  0x04,  0x13,  0x05,  0xe6,  0x06,  0x83,  0x06,  0xf0,  0x07,  0x00,  0x0a,  0x00,  0x0a,  0xf0,
+  0x0c,  0x12,  0x0c,  0x13,  0x0e,  0x13,  0x10,  0x04,  0x10,  0x10,  0x12,  0x1c,  0x19,  0x81,  0x1a,  0x10,
+  0x1c,  0x00,  0x1c,  0x12,  0x1c,  0x13,  0x1d,  0xf7,  0x1e,  0x13,  0x20,  0x1c,  0x20,  0xe7,  0x22,  0x01,
+  0x26,  0x01,  0x30,  0xe7,  0x38,  0x12,  0x3a,  0x55,  0x3f,  0x00,  0x41,  0x58,  0x43,  0x48,  0x46,  0x1c,
+  0x4e,  0xe4,  0x5a,  0x13,  0x68,  0x13,  0x72,  0x14,  0x76,  0x02,  0x77,  0x57,  0x78,  0x03,  0x89,  0x48,
+  0x8a,  0x13,  0x98,  0x80,  0x99,  0x00,  0x9b,  0x00,  0x9c,  0x32,  0xfe,  0x9c,  0xf0,  0x27,  0x02,  0xfe,
+  0xa6,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xfe,  0xc6,  0x01,  0xfe,  0x18,  0x1a,  0x00,  0xfe,  0xc4,  0x01,
+  0xfe,  0x84,  0x01,  0xff,  0x03,  0x00,  0x00,  0x30,  0xfe,  0x01,  0x05,  0xff,  0x40,  0x00,  0x00,  0x0d,
+  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,  0x01,  0x01,  0xff,  0x10,  0xff,  0xff,  0xff,  0x1f,  0x00,  0x00,
+  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,
+  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x38,  0x86,  0x0b,  0x01,  0xfe,  0x96,  0x0f,  0xfe,
+  0x04,  0xf7,  0xfe,  0xc4,  0x01,  0x86,  0x0b,  0x1c,  0x38,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0xfe,
+  0x20,  0xf0,  0xdb,  0x04,  0x5e,  0x59,  0x02,  0xfe,  0xc2,  0x0d,  0x01,  0xfe,  0x22,  0x0e,  0xfe,  0xe9,
+  0x12,  0x02,  0xfe,  0x08,  0x03,  0xfe,  0x28,  0x1c,  0x04,  0xfe,  0xa6,  0x00,  0xfe,  0xdd,  0x12,  0x46,
+  0x12,  0xfe,  0xa6,  0x00,  0xcd,  0xfe,  0x48,  0xf0,  0xfe,  0x80,  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0x9a,
+  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xb8,  0x02,  0xfe,  0x46,  0xf0,  0xfe,  0x4a,  0x02,  0xfe,  0x47,  0xf0,
+  0xfe,  0x50,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x3e,  0x02,  0xfe,  0x44,  0xf0,  0xfe,  0x42,  0x02,  0xfe,
+  0x45,  0xf0,  0xfe,  0x46,  0x02,  0x09,  0x0b,  0xa2,  0x09,  0x06,  0x12,  0xc1,  0x02,  0x27,  0xfe,  0x00,
+  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xfe,  0xed,  0x10,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,  0x10,
+  0x01,  0xfe,  0xee,  0x17,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xfe,  0xa8,  0x00,  0x0f,  0x7d,  0x01,
+  0xc5,  0x02,  0x27,  0x17,  0x5d,  0x4b,  0xc3,  0x01,  0xab,  0x0f,  0x7d,  0x01,  0x9f,  0xfe,  0xbd,  0x10,
+  0x0f,  0x7d,  0x01,  0x9f,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x09,  0x06,  0x12,
+  0xc1,  0x38,  0x19,  0x27,  0xfe,  0x3d,  0xf0,  0xfe,  0xfc,  0x01,  0x28,  0xfe,  0x8e,  0x02,  0xfe,  0x5a,
+  0x1c,  0xdd,  0xfe,  0x14,  0x1c,  0x17,  0xfe,  0x30,  0x00,  0x4b,  0xc3,  0x01,  0xfe,  0xfc,  0x0f,  0x09,
+  0x06,  0x12,  0xc1,  0x02,  0xfe,  0xc6,  0x01,  0x2a,  0x2d,  0x05,  0x10,  0x30,  0xfe,  0x69,  0x10,  0x09,
+  0x06,  0x12,  0xc1,  0xfe,  0x04,  0xec,  0x2d,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x40,  0x81,  0xfe,
+  0x05,  0xf6,  0xfe,  0xa8,  0x00,  0x01,  0xfe,  0x20,  0x17,  0x0a,  0x4f,  0x8d,  0x3a,  0x11,  0x48,  0x1c,
+  0xd3,  0x07,  0x1e,  0x09,  0x51,  0x01,  0xa0,  0x02,  0x27,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0xda,
+  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0xfe,  0x28,  0x10,  0x0f,  0xc7,  0x01,  0x15,  0xed,  0x0f,  0x7e,
+  0x01,  0x15,  0xfe,  0x49,  0x54,  0x77,  0xfe,  0x16,  0x03,  0x07,  0x1e,  0x09,  0x51,  0x01,  0xa0,  0x02,
+  0x27,  0x38,  0x81,  0xfe,  0x02,  0xe8,  0x33,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xf5,  0xfe,  0x07,
+  0x4b,  0xfe,  0x20,  0xf0,  0xdb,  0xfe,  0x40,  0x1c,  0x19,  0xf6,  0xfe,  0x26,  0xf0,  0xfe,  0x74,  0x03,
+  0xfe,  0xa0,  0xf0,  0xfe,  0x62,  0x03,  0xfe,  0x11,  0xf0,  0xdb,  0xfe,  0x0e,  0x10,  0xfe,  0x9f,  0xf0,
+  0xfe,  0x82,  0x03,  0xef,  0x13,  0xfe,  0x11,  0x00,  0x02,  0x54,  0x38,  0xfe,  0x48,  0x1c,  0xef,  0x19,
+  0xf6,  0x35,  0xf6,  0xfe,  0x82,  0xf0,  0xfe,  0x88,  0x03,  0x24,  0x2a,  0xc4,  0x70,  0x16,  0xc4,  0x0f,
+  0x7e,  0x01,  0x15,  0x70,  0x7f,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x40,  0x11,  0x3d,  0x07,  0x3d,  0x09,
+  0xa1,  0x01,  0xa0,  0xfc,  0x11,  0xfe,  0xe4,  0x00,  0x2f,  0xfe,  0xce,  0x03,  0x19,  0x32,  0x1f,  0xfe,
+  0xde,  0x03,  0x01,  0x41,  0xd4,  0xfe,  0xee,  0x03,  0x71,  0x8c,  0xd7,  0xfe,  0xae,  0x06,  0x02,  0x25,
+  0x04,  0x7d,  0x2c,  0x1a,  0xfe,  0x20,  0x05,  0x17,  0x88,  0x01,  0x2e,  0x01,  0x9b,  0x01,  0x9d,  0x35,
+  0xfe,  0x60,  0x02,  0x02,  0xf4,  0xef,  0x38,  0x86,  0x18,  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xf5,
+  0xfe,  0x48,  0x1c,  0x8f,  0x01,  0xf2,  0xb1,  0xfe,  0x96,  0xf0,  0xfe,  0x28,  0x04,  0x2f,  0xfe,  0x2c,
+  0x04,  0x35,  0x27,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x1a,  0xfe,  0x0c,  0x05,  0x4c,  0x97,  0xa3,
+  0x33,  0x84,  0x74,  0x19,  0x32,  0x1f,  0x25,  0x04,  0x7d,  0x2c,  0xfe,  0x10,  0x12,  0x17,  0x88,  0x01,
+  0x2e,  0x35,  0xfe,  0x60,  0x02,  0x02,  0xf4,  0x21,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x5e,
+  0x12,  0x0a,  0x08,  0x06,  0xfe,  0x56,  0x12,  0x23,  0x29,  0x98,  0x01,  0x0c,  0x84,  0x74,  0x1f,  0xfe,
+  0xdc,  0x04,  0x23,  0x29,  0x98,  0x01,  0x0c,  0x1f,  0x25,  0x23,  0x29,  0xba,  0xfe,  0x4c,  0x44,  0xfe,
+  0x32,  0x12,  0x50,  0xfe,  0x44,  0x48,  0x07,  0xfe,  0x93,  0x00,  0xfe,  0x4c,  0x54,  0x77,  0xfe,  0x0c,
+  0x05,  0x81,  0xa3,  0x33,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x48,  0x13,  0x3e,  0x05,  0xfe,
+  0xcc,  0x00,  0xfe,  0x40,  0x13,  0x0a,  0x08,  0x06,  0xea,  0xfe,  0x06,  0x10,  0x23,  0x29,  0xba,  0x0a,
+  0x08,  0x39,  0xe1,  0x17,  0xa6,  0x0a,  0x08,  0x06,  0x59,  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x2e,  0x35,
+  0xfe,  0x66,  0x0d,  0x02,  0x25,  0x3b,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xb7,  0x03,  0x17,
+  0xa6,  0x01,  0x2e,  0x35,  0x27,  0x19,  0x27,  0x02,  0xfe,  0x14,  0x05,  0xfe,  0x42,  0x5b,  0x86,  0x18,
+  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xf5,  0x17,  0x78,  0xfe,  0x07,  0x80,  0xfe,  0x31,  0x44,  0x0a,
+  0x08,  0x0b,  0x99,  0xfe,  0x20,  0x80,  0x05,  0x18,  0xfe,  0x70,  0x12,  0x73,  0x08,  0x06,  0xfe,  0x60,
+  0x13,  0x04,  0xfe,  0xa2,  0x00,  0x2c,  0x1a,  0xfe,  0xac,  0x05,  0xfe,  0x31,  0xe4,  0x5f,  0x73,  0x08,
+  0x0b,  0xfe,  0x4a,  0x13,  0x04,  0xfe,  0xa0,  0x00,  0x2c,  0xfe,  0x42,  0x12,  0x62,  0x2f,  0xfe,  0x6c,
+  0x05,  0x19,  0x32,  0xf7,  0x01,  0x0c,  0x26,  0xfe,  0xc4,  0x05,  0x11,  0xfe,  0xe3,  0x00,  0x24,  0x73,
+  0xfe,  0x4a,  0xf0,  0xfe,  0x96,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x90,  0x05,  0xab,  0x20,  0xfe,  0x21,
+  0x00,  0xa8,  0x20,  0xfe,  0x22,  0x00,  0xa2,  0x20,  0x8d,  0xfe,  0x09,  0x48,  0x01,  0x0c,  0x26,  0xfe,
+  0xc4,  0x05,  0xfe,  0xe2,  0x08,  0x73,  0x08,  0xe0,  0x59,  0x01,  0x99,  0x20,  0x06,  0x16,  0xe8,  0x4b,
+  0xfe,  0x27,  0x01,  0x0a,  0x08,  0x39,  0xb0,  0x46,  0x01,  0xb6,  0x17,  0xa6,  0x0a,  0x08,  0x06,  0x59,
+  0x17,  0xfe,  0x0d,  0x00,  0x01,  0x2e,  0x01,  0x9b,  0x01,  0x9d,  0x35,  0xfe,  0x66,  0x0d,  0x02,  0x25,
+  0x04,  0xfe,  0x9c,  0x00,  0x2c,  0xfe,  0x3e,  0x12,  0x04,  0x5b,  0x2c,  0xfe,  0x36,  0x13,  0x46,  0x01,
+  0xb6,  0x26,  0xfe,  0x3c,  0x06,  0x0f,  0x06,  0x73,  0x08,  0x22,  0xfe,  0x02,  0x12,  0x69,  0x01,  0xfe,
+  0xd0,  0x14,  0x1f,  0xfe,  0x32,  0x06,  0x11,  0xc8,  0x01,  0x41,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x5b,
+  0xc2,  0x0e,  0x5b,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0x62,  0x12,  0x04,  0x56,  0x2c,  0xf1,  0x01,
+  0xfe,  0x40,  0x19,  0x01,  0xfe,  0xaa,  0x19,  0xee,  0xd2,  0xec,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,
+  0x6c,  0x80,  0x1b,  0x58,  0xd1,  0xd2,  0x8b,  0x46,  0x01,  0xb6,  0x26,  0xfe,  0xa6,  0x06,  0x73,  0x08,
+  0x1d,  0xa7,  0x7c,  0x0f,  0x5d,  0x01,  0xfe,  0xfe,  0x14,  0x1f,  0xfe,  0x9c,  0x06,  0x11,  0xc8,  0x01,
+  0x41,  0x11,  0xfe,  0xe5,  0x00,  0x04,  0x56,  0xc2,  0x0e,  0x56,  0x09,  0x06,  0x01,  0xb6,  0xfc,  0x76,
+  0x8f,  0x01,  0xf2,  0xb1,  0x11,  0xfe,  0xe2,  0x00,  0x2f,  0xfe,  0xbe,  0x06,  0x19,  0x32,  0xd7,  0xfe,
+  0xda,  0x06,  0x83,  0xfe,  0x78,  0x07,  0xd4,  0xfe,  0x80,  0x07,  0x71,  0x8c,  0x02,  0x25,  0x0a,  0x08,
+  0x0b,  0xfe,  0x2e,  0x12,  0x14,  0x18,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,
+  0x14,  0x00,  0x01,  0x0c,  0xfe,  0x99,  0xa4,  0x01,  0x0c,  0x14,  0x00,  0x02,  0xfe,  0x3e,  0x08,  0x6f,
+  0x08,  0x1d,  0xea,  0x0a,  0x08,  0x1d,  0xfe,  0x30,  0x13,  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x0c,  0x14,
+  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x00,  0x01,  0x0c,  0x14,  0x06,  0x01,  0x0c,  0x14,
+  0x00,  0x02,  0xfe,  0xe6,  0x0b,  0x69,  0xfe,  0x9a,  0x81,  0x6d,  0x8d,  0xfe,  0x09,  0x6f,  0xfe,  0x93,
+  0x45,  0x1a,  0xfe,  0x88,  0x07,  0x2f,  0xfe,  0x60,  0x07,  0x19,  0x32,  0xd7,  0xfe,  0x58,  0x07,  0x71,
+  0x8c,  0x83,  0xfe,  0x78,  0x07,  0x02,  0x25,  0x01,  0x41,  0x02,  0xfe,  0xbe,  0x06,  0x14,  0x22,  0x02,
+  0xfe,  0xbe,  0x06,  0xfe,  0x9c,  0xf7,  0xfe,  0xf4,  0x07,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x52,
+  0xfe,  0xd6,  0x07,  0x0e,  0x65,  0x12,  0x66,  0x0a,  0x4f,  0x5f,  0x3a,  0x01,  0xfe,  0xd6,  0x18,  0x05,
+  0x10,  0x85,  0xfe,  0x83,  0xe7,  0xfe,  0x95,  0x00,  0xa8,  0xfe,  0x03,  0x40,  0x0a,  0x4f,  0x78,  0x3a,
+  0x01,  0xbc,  0xb5,  0xfe,  0x1f,  0x40,  0x16,  0x67,  0x01,  0xf8,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,
+  0xfe,  0x34,  0x51,  0xfe,  0xb6,  0x51,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0e,  0x63,  0x12,  0x64,
+  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x0e,  0x42,  0x12,  0x43,
+  0x41,  0x0a,  0x08,  0x5f,  0xb0,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0e,  0x65,  0x12,  0x66,  0x0a,
+  0x08,  0x78,  0xd1,  0x01,  0xbc,  0xfe,  0x1f,  0x80,  0x16,  0x67,  0xfe,  0x34,  0x90,  0xfe,  0xb6,  0x90,
+  0x0e,  0x44,  0x12,  0x45,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0e,  0x63,  0x12,  0x64,  0xfe,  0x28,
+  0x90,  0xfe,  0xaa,  0x90,  0x0e,  0x42,  0x12,  0x43,  0x0e,  0x31,  0x12,  0x3f,  0x24,  0x0e,  0x53,  0x0e,
+  0x68,  0x0a,  0x4f,  0x22,  0x3a,  0x38,  0x07,  0xa5,  0x2f,  0xfe,  0x5e,  0x08,  0xfe,  0x9e,  0xf0,  0xfe,
+  0x72,  0x08,  0xcc,  0x1a,  0x32,  0x38,  0x72,  0xfe,  0xed,  0x10,  0xaa,  0xfe,  0x96,  0x08,  0xac,  0xfe,
+  0xb2,  0x08,  0x83,  0xfe,  0x8a,  0x08,  0xd4,  0xfe,  0x90,  0x08,  0x71,  0x8c,  0x02,  0x25,  0x01,  0x41,
+  0xfe,  0xc9,  0x10,  0x14,  0x22,  0xfe,  0xc9,  0x10,  0x6f,  0x08,  0x06,  0xfe,  0x10,  0x12,  0x6f,  0x08,
+  0x0b,  0x4e,  0x0a,  0x08,  0x0b,  0xfe,  0x8e,  0x12,  0xfe,  0x2e,  0x1c,  0xad,  0x6f,  0x08,  0x06,  0x4e,
+  0x6f,  0x08,  0x0b,  0xfe,  0x7a,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0xcc,  0x09,  0xfe,
+  0xac,  0xf0,  0xfe,  0xfa,  0x08,  0x02,  0xfe,  0xd8,  0x09,  0xfe,  0xb7,  0xf0,  0xfe,  0xf6,  0x08,  0xfe,
+  0x02,  0xf6,  0x1d,  0x69,  0xfe,  0x70,  0x18,  0xfe,  0xf1,  0x18,  0xfe,  0x40,  0x55,  0xfe,  0xe1,  0x55,
+  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x19,  0x92,  0xfe,  0x8c,
+  0xf0,  0xfe,  0xf6,  0x08,  0xfe,  0xac,  0xf0,  0xfe,  0xea,  0x08,  0xfe,  0x34,  0x1c,  0xfe,  0xcb,  0x10,
+  0xfe,  0xad,  0xf0,  0xfe,  0x06,  0x09,  0x02,  0xfe,  0x12,  0x0b,  0xfe,  0x36,  0x1c,  0xfe,  0xbf,  0x10,
+  0xfe,  0x2b,  0xf0,  0x92,  0xfe,  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xfe,  0xe1,  0xcd,  0xfe,  0xd2,  0xf0,
+  0x92,  0xfe,  0x76,  0x18,  0x1b,  0x18,  0x1a,  0x92,  0x04,  0xe7,  0x1b,  0x06,  0x1a,  0x92,  0xaa,  0x57,
+  0xac,  0x57,  0xfe,  0x34,  0x1c,  0xfe,  0x36,  0x1c,  0xfe,  0x89,  0x10,  0x8f,  0x62,  0x3b,  0x17,  0xa6,
+  0x01,  0x2e,  0x13,  0xfe,  0x35,  0x00,  0x35,  0x54,  0x13,  0x90,  0x02,  0x54,  0xf9,  0xaf,  0x0b,  0xfe,
+  0x1a,  0x12,  0x50,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xeb,  0xde,  0xfe,  0x74,
+  0x18,  0x91,  0x93,  0x1a,  0xfe,  0xc8,  0x08,  0x02,  0x57,  0x0a,  0x08,  0x5f,  0x2e,  0x04,  0x31,  0x2b,
+  0x3f,  0x0e,  0x44,  0x12,  0x45,  0x82,  0x31,  0x5a,  0x3f,  0xfe,  0x6c,  0x18,  0xfe,  0xed,  0x18,  0xfe,
+  0x44,  0x54,  0xfe,  0xe5,  0x54,  0x36,  0x44,  0x21,  0x45,  0x04,  0x53,  0x2b,  0x68,  0x91,  0xfe,  0xe3,
+  0x54,  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x91,  0xfe,  0xe3,  0x54,  0x93,  0xc9,  0x52,  0xfe,  0xc8,
+  0x08,  0x02,  0x57,  0xfe,  0x37,  0xf0,  0xfe,  0xd4,  0x09,  0xfe,  0x8b,  0xf0,  0xfe,  0x5a,  0x09,  0x02,
+  0x57,  0xf9,  0xaf,  0x0b,  0x28,  0xfe,  0xf4,  0x0a,  0x36,  0x53,  0x21,  0x68,  0x52,  0xfe,  0x38,  0x0a,
+  0x07,  0xfe,  0xc0,  0x07,  0x46,  0x61,  0x00,  0xd9,  0xfe,  0x01,  0x59,  0xfe,  0x52,  0xf0,  0xfe,  0x06,
+  0x0a,  0x91,  0x96,  0xfe,  0x1e,  0x0a,  0x36,  0x53,  0x91,  0xfe,  0xe3,  0x54,  0x4d,  0x53,  0x6e,  0x68,
+  0xfe,  0x14,  0x58,  0xfe,  0x95,  0x58,  0x02,  0x57,  0x36,  0x53,  0x21,  0x68,  0xfe,  0x14,  0x59,  0xfe,
+  0x95,  0x59,  0xeb,  0x4d,  0x53,  0x4d,  0x68,  0x02,  0x57,  0x0a,  0x08,  0x5f,  0xfe,  0x82,  0x12,  0x0a,
+  0x08,  0x22,  0xfe,  0x66,  0x13,  0x2a,  0x67,  0x70,  0xd0,  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,
+  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6b,  0x33,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,
+  0x52,  0xfe,  0xd0,  0x08,  0x04,  0x65,  0x2b,  0x66,  0x0e,  0xb3,  0x12,  0x90,  0x4d,  0x65,  0x6e,  0x66,
+  0x01,  0xbc,  0xb5,  0x6b,  0x33,  0x16,  0x67,  0x82,  0x31,  0x5a,  0x3f,  0x36,  0x44,  0x21,  0x45,  0x93,
+  0xc9,  0xfe,  0x04,  0xfa,  0x31,  0xfe,  0x05,  0xfa,  0x3f,  0x01,  0xf8,  0xfe,  0x36,  0x10,  0x24,  0x0e,
+  0xb3,  0x0e,  0x90,  0x36,  0x44,  0x21,  0x45,  0xad,  0x0a,  0x08,  0x22,  0x1a,  0xfe,  0xd0,  0x08,  0x36,
+  0x42,  0x21,  0x43,  0x0a,  0x08,  0xfe,  0xf7,  0x00,  0x3a,  0x04,  0x63,  0x2b,  0x64,  0xfe,  0x10,  0x58,
+  0xfe,  0x91,  0x58,  0x4d,  0x53,  0x6e,  0x68,  0x02,  0xfe,  0xee,  0x09,  0x0a,  0x08,  0x22,  0x1a,  0xfe,
+  0xd0,  0x08,  0x0a,  0x08,  0xfe,  0xf7,  0x00,  0x3a,  0xeb,  0xde,  0x69,  0xfe,  0x10,  0x90,  0xfe,  0x92,
+  0x90,  0xfe,  0xd3,  0x10,  0x3e,  0x05,  0xca,  0x1a,  0xfe,  0x02,  0x09,  0x11,  0xca,  0xf9,  0xaf,  0x0b,
+  0xfe,  0x14,  0x13,  0x04,  0x42,  0x2b,  0x43,  0x52,  0xfe,  0x02,  0x09,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,
+  0x58,  0x02,  0x57,  0x24,  0x46,  0xfe,  0x19,  0x80,  0xfe,  0xf1,  0x10,  0x0a,  0x08,  0x0b,  0xa7,  0xfe,
+  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xfe,  0x94,  0x10,  0xfe,  0x6c,  0x19,  0x4d,  0x42,  0xfe,  0xed,  0x19,
+  0x6e,  0x43,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x1b,  0xfe,  0x00,  0xff,  0x30,
+  0xfe,  0x7a,  0x10,  0xcd,  0xfe,  0xd2,  0xf0,  0xfe,  0x8c,  0x0b,  0xfe,  0x76,  0x18,  0x1b,  0x18,  0xa9,
+  0x04,  0xe7,  0x1b,  0x06,  0x87,  0x13,  0xfe,  0x16,  0x00,  0x02,  0x54,  0xfe,  0xd1,  0xf0,  0xfe,  0xc2,
+  0x0b,  0x17,  0xa5,  0x01,  0x2e,  0x13,  0xfe,  0x17,  0x00,  0xfe,  0x48,  0x10,  0xfe,  0xce,  0xf0,  0xfe,
+  0xaa,  0x0b,  0x13,  0xfe,  0x21,  0x00,  0x02,  0x54,  0xfe,  0xcd,  0xf0,  0xfe,  0xb6,  0x0b,  0x13,  0xfe,
+  0x22,  0x00,  0x02,  0x54,  0xfe,  0xcb,  0xf0,  0xfe,  0xc2,  0x0b,  0x13,  0xfe,  0x24,  0x00,  0x02,  0x54,
+  0xfe,  0xd0,  0xf0,  0xfe,  0xcc,  0x0b,  0x13,  0xae,  0xdf,  0xfe,  0xcf,  0xf0,  0xfe,  0xd6,  0x0b,  0x13,
+  0x8d,  0xdc,  0xfe,  0xcc,  0xf0,  0xfe,  0xe6,  0x0b,  0xfe,  0x84,  0x80,  0xaf,  0x22,  0xfe,  0xd5,  0x12,
+  0x13,  0xfe,  0x12,  0x00,  0x2f,  0xfe,  0xe6,  0x0b,  0x19,  0x32,  0xaa,  0x25,  0xac,  0x25,  0x38,  0xfc,
+  0x2f,  0xfe,  0xfa,  0x0b,  0x19,  0x32,  0x83,  0xfe,  0x16,  0x0c,  0x71,  0x8c,  0xaa,  0xfe,  0xf4,  0x07,
+  0xac,  0xfe,  0xf4,  0x07,  0x02,  0x25,  0x01,  0x41,  0xfe,  0xdb,  0x10,  0x11,  0xfe,  0xe8,  0x00,  0x8f,
+  0x84,  0x74,  0xfe,  0x89,  0xf0,  0x25,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0x01,  0x0c,  0x84,  0x74,  0x1f,
+  0x25,  0x23,  0x29,  0x98,  0x35,  0xfe,  0x4e,  0x0c,  0x19,  0x32,  0x02,  0xfe,  0x42,  0x0c,  0xcc,  0x4e,
+  0x13,  0xfe,  0x42,  0x00,  0x02,  0x54,  0xa4,  0x06,  0xfe,  0x81,  0x49,  0xfe,  0xcc,  0x12,  0x0a,  0x08,
+  0x0b,  0xf1,  0x13,  0x00,  0x60,  0x0b,  0xfe,  0x6a,  0x12,  0x60,  0xfe,  0x28,  0x00,  0x28,  0xfe,  0x94,
+  0x0d,  0x0f,  0x7e,  0x01,  0x15,  0x05,  0x00,  0x87,  0x37,  0xfe,  0x28,  0x00,  0x02,  0xfe,  0x94,  0x0d,
+  0x01,  0x9b,  0x01,  0x9d,  0x0f,  0xc7,  0x01,  0xfe,  0xf0,  0x0e,  0xb9,  0x07,  0x3d,  0x09,  0xa1,  0x01,
+  0x40,  0x11,  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0x02,  0x27,  0x13,  0xfe,  0x44,  0x00,  0x60,
+  0x0b,  0xa7,  0x37,  0x0b,  0xfe,  0xc0,  0x10,  0x01,  0x99,  0x37,  0x0b,  0xfe,  0xb6,  0x10,  0x01,  0x99,
+  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xfe,  0x0a,  0x13,  0x37,  0x0b,  0x13,  0xfe,  0x43,  0x00,  0xc0,
+  0x0a,  0x4f,  0x0b,  0x3a,  0x01,  0x9b,  0x01,  0x9d,  0xb9,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,  0x11,
+  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,  0x86,  0x0b,  0xb9,  0x1c,  0xd3,  0x02,  0xfe,  0x4c,  0x03,
+  0x0a,  0x08,  0x0b,  0xa9,  0x37,  0x0b,  0x13,  0x00,  0xfe,  0x54,  0x10,  0x6f,  0x08,  0x1d,  0xfe,  0x50,
+  0x12,  0x0a,  0x08,  0x1d,  0xfe,  0x48,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x52,  0x0d,
+  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x58,  0x0d,  0x0a,  0x4f,  0x1d,  0x3a,  0xfe,  0x95,  0x10,
+  0x13,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0b,  0x69,  0xfe,  0x26,  0x10,  0x13,  0xfe,  0x13,  0x00,
+  0xdc,  0x13,  0xfe,  0x47,  0x00,  0xa8,  0x13,  0xfe,  0x41,  0x00,  0xa2,  0x13,  0xfe,  0x24,  0x00,  0x04,
+  0x7d,  0x2c,  0x28,  0xf4,  0x69,  0xfe,  0x04,  0xe6,  0x1d,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0xb9,
+  0x01,  0xfe,  0xf8,  0x0e,  0x02,  0x27,  0xdd,  0x17,  0x0b,  0x4b,  0xfb,  0xe5,  0x17,  0xfe,  0x31,  0x00,
+  0x4b,  0xc3,  0x01,  0xfe,  0xfc,  0x0f,  0x02,  0xfe,  0xc6,  0x01,  0x1c,  0xfe,  0x06,  0xec,  0xfe,  0xb9,
+  0x00,  0x89,  0x37,  0x39,  0xc6,  0x30,  0x1c,  0xfe,  0x06,  0xea,  0xfe,  0xb9,  0x00,  0xfe,  0x47,  0x4b,
+  0x7c,  0xfe,  0x75,  0x57,  0x04,  0x5e,  0xfe,  0x98,  0x56,  0xfe,  0x28,  0x12,  0x0f,  0x7e,  0xfe,  0xfa,
+  0x14,  0x46,  0xed,  0x0f,  0xc7,  0xfe,  0xf0,  0x14,  0xfe,  0x49,  0x54,  0x95,  0xfe,  0x08,  0x0e,  0x0f,
+  0x1e,  0xfe,  0xe4,  0x14,  0xfe,  0x44,  0x48,  0x02,  0xfe,  0x4c,  0x03,  0x0f,  0x5e,  0xfe,  0xc8,  0x14,
+  0x89,  0x37,  0x39,  0xc6,  0x30,  0x1c,  0xfe,  0xce,  0x47,  0xfe,  0xbd,  0x13,  0x02,  0x27,  0x2a,  0x2d,
+  0x05,  0x10,  0xfe,  0x78,  0x12,  0x24,  0x16,  0x5d,  0x16,  0xb2,  0x2a,  0x48,  0x46,  0x4b,  0x48,  0xcc,
+  0xd9,  0xfe,  0xbc,  0xf0,  0xfe,  0xa4,  0x0e,  0x07,  0x06,  0x16,  0x5d,  0x01,  0xfe,  0xb0,  0x16,  0x04,
+  0xfe,  0x38,  0x01,  0x2b,  0xfe,  0x3a,  0x01,  0x52,  0xfe,  0xa8,  0x0e,  0x04,  0xfe,  0x38,  0x01,  0x1b,
+  0xfe,  0xf0,  0xff,  0x0e,  0xfe,  0x60,  0x01,  0x04,  0xfe,  0x3a,  0x01,  0x0e,  0xfe,  0x62,  0x01,  0x20,
+  0x06,  0x16,  0x48,  0xfe,  0x04,  0xec,  0x2d,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x40,  0x81,  0xfe,
+  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x20,  0x17,  0x11,  0x48,  0xd3,  0x07,  0x06,  0x03,  0x24,
+  0x03,  0x2a,  0x5d,  0xfe,  0xf7,  0x12,  0x2a,  0xb2,  0x70,  0x16,  0xb2,  0x05,  0xa5,  0xfe,  0x93,  0x13,
+  0xfe,  0x24,  0x1c,  0x17,  0x18,  0x4b,  0xfb,  0xe5,  0xfe,  0xd9,  0x10,  0x9a,  0xfe,  0x03,  0xdc,  0xfe,
+  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0x9a,  0xfe,  0x03,  0xdc,  0x24,  0xfe,  0x70,  0x57,  0xfe,  0x33,
+  0x54,  0xfe,  0x3b,  0x54,  0xfe,  0x80,  0x5d,  0x03,  0xfe,  0x03,  0x57,  0x9a,  0x24,  0xfe,  0x00,  0xcc,
+  0x03,  0xfe,  0x03,  0x57,  0x9a,  0x7f,  0x03,  0x01,  0xfe,  0x50,  0x17,  0x3e,  0x05,  0x48,  0xfe,  0x0a,
+  0x13,  0x07,  0x1e,  0x09,  0x51,  0xdc,  0x01,  0x9b,  0x01,  0x9d,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,
+  0x11,  0xfe,  0xe9,  0x00,  0x0a,  0x08,  0x8d,  0xfe,  0x52,  0x13,  0x01,  0xfe,  0xe2,  0x16,  0xfe,  0x1e,
+  0x1c,  0xfe,  0x14,  0x90,  0x0e,  0xfe,  0x64,  0x01,  0xfe,  0x16,  0x90,  0x0e,  0xfe,  0x66,  0x01,  0x0a,
+  0x08,  0x78,  0xea,  0xfe,  0x03,  0x80,  0x72,  0x4c,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,
+  0x01,  0xa0,  0xfe,  0x62,  0x08,  0x70,  0x4c,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,  0x01,
+  0xa0,  0x6b,  0x33,  0x11,  0x7b,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x97,  0x01,  0x79,  0x03,  0xfe,  0x08,
+  0x1c,  0x04,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x04,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x04,
+  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x04,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,
+  0x20,  0x8b,  0x16,  0xfe,  0xb9,  0x00,  0x24,  0x0e,  0x5b,  0x0e,  0x56,  0x20,  0x10,  0x16,  0x2d,  0x16,
+  0x3c,  0x50,  0xa4,  0xfe,  0x93,  0x00,  0x07,  0x2d,  0x09,  0x3c,  0x1c,  0x01,  0x79,  0x81,  0x11,  0x7b,
+  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xd6,  0x0f,  0xdd,  0x8f,  0xfe,  0x14,  0x1c,  0xfe,  0x10,
+  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x1c,  0xfe,  0x0c,  0x14,  0x89,  0xfe,  0x07,  0xe6,  0x39,  0xfe,  0xce,
+  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x99,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0xda,  0x0f,  0x1e,
+  0x01,  0x15,  0x05,  0x10,  0xe1,  0xfe,  0x44,  0x58,  0x4c,  0xfe,  0x01,  0xec,  0xc3,  0xfe,  0x9e,  0x40,
+  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1d,  0xa3,  0x33,  0x01,  0xfe,  0xf8,  0x0e,  0xfe,  0xc9,
+  0x10,  0x03,  0x38,  0x84,  0x74,  0x23,  0x29,  0xba,  0x05,  0x1d,  0xfe,  0x48,  0x12,  0x05,  0x0b,  0xfe,
+  0x4c,  0x12,  0x05,  0x18,  0xfe,  0x30,  0x12,  0x05,  0xd5,  0x1a,  0xfe,  0xa0,  0x11,  0x05,  0xfe,  0x23,
+  0x00,  0x1a,  0xfe,  0xac,  0x11,  0x05,  0x06,  0x1a,  0xa9,  0x05,  0x22,  0xfe,  0x12,  0x12,  0x05,  0x00,
+  0x1a,  0x25,  0x17,  0xd5,  0x01,  0x2e,  0xce,  0x3b,  0x01,  0x0c,  0x83,  0x41,  0x03,  0x3b,  0x11,  0xfe,
+  0xcc,  0x00,  0x02,  0x27,  0x3b,  0x3e,  0x05,  0xca,  0xfe,  0xe3,  0x13,  0x36,  0x42,  0x21,  0x43,  0x52,
+  0xfe,  0x5e,  0x11,  0x0a,  0x08,  0x5f,  0xfe,  0x72,  0x12,  0x82,  0x31,  0x5a,  0x3f,  0x93,  0xc9,  0x95,
+  0xfe,  0x28,  0x11,  0x2a,  0x67,  0xfe,  0x26,  0x13,  0x04,  0xb3,  0x2b,  0x90,  0x52,  0xfe,  0x78,  0x0d,
+  0x0e,  0x65,  0x12,  0x66,  0x24,  0x0e,  0xb3,  0x0e,  0x90,  0x01,  0xbc,  0x20,  0x8b,  0x72,  0x16,  0x67,
+  0x01,  0xf8,  0x82,  0x31,  0x5a,  0x3f,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x31,
+  0xfe,  0x05,  0xfa,  0x3f,  0xfe,  0x91,  0x10,  0x04,  0x44,  0x2b,  0x45,  0xfe,  0x40,  0x56,  0xfe,  0xe1,
+  0x56,  0x0e,  0x44,  0x12,  0x45,  0xab,  0x82,  0x31,  0x5a,  0x3f,  0x93,  0xc9,  0x04,  0x63,  0x2b,  0x64,
+  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0e,  0x63,  0x12,  0x64,  0x0a,  0x08,  0x5f,  0xfe,  0x1e,  0x12,
+  0x2a,  0x67,  0xfe,  0x1f,  0x40,  0x04,  0x65,  0x2b,  0x66,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x04,
+  0x44,  0x2b,  0x45,  0xfe,  0x34,  0x50,  0xfe,  0xb6,  0x50,  0x04,  0x63,  0x2b,  0x64,  0xfe,  0x08,  0x50,
+  0xfe,  0x8a,  0x50,  0x04,  0x42,  0x2b,  0x43,  0xfe,  0x28,  0x50,  0xfe,  0xaa,  0x50,  0x02,  0x9c,  0x20,
+  0x06,  0x16,  0xfa,  0x02,  0x7a,  0x3b,  0x01,  0x0c,  0x1f,  0x55,  0x23,  0x29,  0xba,  0x05,  0x06,  0x28,
+  0x55,  0x3e,  0x05,  0xca,  0x28,  0x7a,  0x01,  0xf2,  0x1b,  0x58,  0x1a,  0x55,  0x0a,  0x08,  0x0b,  0xe4,
+  0x36,  0x42,  0x21,  0x43,  0xfe,  0x0a,  0x55,  0x30,  0xfe,  0x8b,  0x55,  0x4d,  0x42,  0x6e,  0x43,  0xfe,
+  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x7a,  0xde,  0xfe,  0x0a,  0x45,  0xfe,  0x19,  0x41,  0x02,  0x7a,
+  0x3b,  0x01,  0x0c,  0x1f,  0xc0,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0x60,  0x18,  0xfe,  0x94,  0x12,  0x60,
+  0x0b,  0x59,  0x02,  0x55,  0x2f,  0xb0,  0x19,  0x32,  0x1f,  0xc0,  0x23,  0x29,  0x98,  0x05,  0x18,  0x28,
+  0x55,  0x01,  0x0c,  0x1f,  0xc0,  0x23,  0x29,  0xfe,  0xe8,  0x09,  0x50,  0x04,  0xfe,  0x9c,  0x00,  0x2c,
+  0x30,  0xfe,  0xbb,  0x45,  0x60,  0x00,  0x4e,  0x37,  0x06,  0xa4,  0x58,  0xfe,  0xc0,  0x14,  0xfe,  0xf8,
+  0x14,  0xb1,  0x3e,  0x05,  0xc8,  0xfe,  0x16,  0x13,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xa9,  0x04,  0x56,
+  0x2c,  0x30,  0x62,  0x02,  0x7a,  0xfe,  0xc0,  0x5d,  0xfe,  0xe4,  0x14,  0xfe,  0x03,  0x17,  0x04,  0x5b,
+  0xc2,  0x0e,  0x5b,  0x62,  0x3b,  0x01,  0x0c,  0x26,  0x9c,  0x01,  0xfe,  0xd0,  0x14,  0x02,  0x9c,  0x2f,
+  0xfe,  0xb4,  0x12,  0x19,  0x32,  0x1f,  0x55,  0x23,  0x29,  0x98,  0x05,  0x06,  0x28,  0x55,  0xfe,  0xf6,
+  0x14,  0xfe,  0x42,  0x58,  0xfe,  0x70,  0x14,  0xfe,  0x92,  0x14,  0xb1,  0xfe,  0x4a,  0xf4,  0x0b,  0x1a,
+  0x55,  0xfe,  0x4a,  0xf4,  0x06,  0xd8,  0x3e,  0x05,  0xc8,  0xd1,  0x02,  0x7a,  0x04,  0x56,  0xc2,  0x0e,
+  0x56,  0x62,  0x3b,  0x01,  0x0c,  0x26,  0x9c,  0x01,  0xfe,  0xfe,  0x14,  0x02,  0x9c,  0x26,  0xe2,  0x76,
+  0xf7,  0x76,  0x03,  0x35,  0xfe,  0x18,  0x13,  0x71,  0xfe,  0x18,  0x13,  0x62,  0x3b,  0x01,  0x0c,  0xfe,
+  0xe3,  0x10,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x1b,  0xfe,  0xff,  0x7f,  0xfe,  0x30,
+  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x1b,  0x58,  0xfe,
+  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x07,  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0x03,  0x07,
+  0x6a,  0xff,  0x02,  0x00,  0x57,  0x6c,  0x80,  0xfe,  0x0b,  0x58,  0x03,  0x0f,  0x5b,  0x01,  0x9f,  0x0f,
+  0x56,  0x01,  0x9f,  0x03,  0xd0,  0x1b,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x22,  0x6c,
+  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x6b,  0x33,  0x0e,  0x63,
+  0x12,  0x64,  0x4d,  0x44,  0x6e,  0x45,  0x03,  0xfe,  0x62,  0x18,  0xfe,  0x82,  0x5a,  0xfe,  0xe1,  0x1a,
+  0xbe,  0xfe,  0x02,  0x58,  0x03,  0x01,  0xfe,  0x40,  0x19,  0xfe,  0x42,  0x48,  0x69,  0x50,  0x7c,  0x01,
+  0x0c,  0x1f,  0xfe,  0xc8,  0x14,  0x23,  0x29,  0xfe,  0xe9,  0x09,  0xfe,  0xc1,  0x59,  0x01,  0x0c,  0x1f,
+  0xfe,  0xc8,  0x14,  0x23,  0x29,  0xfe,  0xe8,  0x0a,  0x04,  0xfe,  0x9e,  0x00,  0x2c,  0xfe,  0xc2,  0x12,
+  0x24,  0xb8,  0x1d,  0xe4,  0x60,  0xd6,  0x77,  0xfe,  0x18,  0x14,  0x59,  0x07,  0x06,  0x09,  0xd6,  0xa4,
+  0xfe,  0x00,  0x10,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa8,  0xff,  0x02,  0x83,  0x55,  0xb8,
+  0x18,  0xfe,  0x12,  0x13,  0x61,  0xfe,  0x30,  0x00,  0x95,  0xf3,  0x09,  0x88,  0x07,  0x06,  0xfe,  0x56,
+  0x10,  0xb8,  0x0b,  0xfe,  0x16,  0x13,  0x61,  0xfe,  0x64,  0x00,  0x95,  0xf3,  0x0f,  0xfe,  0x64,  0x00,
+  0x09,  0xae,  0x07,  0x06,  0xfe,  0x28,  0x10,  0xb8,  0x06,  0xfe,  0x5e,  0x13,  0x61,  0xfe,  0xc8,  0x00,
+  0x95,  0xf3,  0x0f,  0xfe,  0xc8,  0x00,  0x09,  0x5d,  0x07,  0x06,  0xab,  0x61,  0xfe,  0x90,  0x01,  0x96,
+  0xfe,  0x7e,  0x14,  0x7c,  0xad,  0xfe,  0x43,  0xf4,  0xb2,  0xfe,  0x56,  0xf0,  0xfe,  0x90,  0x14,  0xfe,
+  0x04,  0xf4,  0x6a,  0xfe,  0x43,  0xf4,  0xae,  0xfe,  0xf3,  0x10,  0xb7,  0x01,  0xf1,  0x1b,  0x58,  0xda,
+  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x8b,  0x96,  0xfe,  0xc2,  0x14,  0x7c,  0xfe,  0x14,  0x10,  0xfe,
+  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0xec,  0x96,  0xfe,  0xc2,  0x14,  0xd2,  0xec,  0xa2,  0x50,  0x7c,  0x07,
+  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x03,  0x50,  0x07,  0x0b,  0x03,  0x14,  0x06,  0x01,  0x0c,
+  0x26,  0xfe,  0xfc,  0x14,  0x14,  0x0b,  0x01,  0x0c,  0x26,  0xfe,  0xfc,  0x14,  0x14,  0x18,  0x01,  0x0c,
+  0x26,  0xfe,  0xfc,  0x14,  0x76,  0xfe,  0x89,  0x49,  0x01,  0x0c,  0x03,  0x14,  0x06,  0x01,  0x0c,  0x26,
+  0xb4,  0x14,  0x18,  0x01,  0x0c,  0x26,  0xb4,  0x14,  0x06,  0x01,  0x0c,  0x26,  0xb4,  0xfe,  0x89,  0x49,
+  0x01,  0x0c,  0x26,  0xb4,  0x76,  0xfe,  0x89,  0x4a,  0x01,  0x0c,  0x03,  0x50,  0x03,  0x2a,  0xe8,  0x05,
+  0x06,  0xfe,  0x44,  0x13,  0xb5,  0x16,  0xe8,  0xfe,  0x49,  0xf4,  0x00,  0x59,  0x76,  0xce,  0x62,  0xfe,
+  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf7,  0x01,  0x0c,  0x3e,  0x05,  0xfe,  0xe3,  0x00,  0xfe,  0x20,  0x13,
+  0x1f,  0xfe,  0x80,  0x15,  0x24,  0x16,  0xfa,  0x01,  0x41,  0x2a,  0xfa,  0x05,  0x06,  0x4e,  0x0a,  0x4f,
+  0x06,  0x3a,  0x03,  0x0e,  0x5c,  0x12,  0x8e,  0xfe,  0x43,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1e,
+  0x12,  0x49,  0xee,  0x94,  0x01,  0x47,  0xfe,  0x90,  0x4d,  0xe6,  0x10,  0xfe,  0xc5,  0x59,  0x01,  0x47,
+  0xfe,  0x8d,  0x56,  0xbe,  0x49,  0x03,  0x49,  0x21,  0x8e,  0x01,  0x15,  0x49,  0x94,  0x01,  0x47,  0xe9,
+  0x10,  0xe6,  0x10,  0x21,  0x5c,  0x61,  0x1e,  0x87,  0x0f,  0x5e,  0x01,  0xc5,  0x03,  0x0e,  0x5c,  0x12,
+  0x8e,  0xfe,  0xc3,  0x58,  0x01,  0x15,  0x05,  0x10,  0xfe,  0x1a,  0x12,  0x49,  0xee,  0x94,  0x01,  0x47,
+  0xe9,  0x10,  0xfe,  0x80,  0x4d,  0xfe,  0xc5,  0x59,  0x01,  0x47,  0x49,  0x03,  0x49,  0x21,  0x5c,  0x01,
+  0x15,  0x49,  0x94,  0x01,  0x47,  0xe9,  0x10,  0xe6,  0x10,  0x21,  0x5c,  0x61,  0x1e,  0x87,  0x0f,  0x5e,
+  0x01,  0xc5,  0x03,  0x0e,  0x5c,  0x12,  0x8e,  0xfe,  0x43,  0x58,  0x01,  0x15,  0xfe,  0x42,  0x48,  0x94,
+  0x01,  0x47,  0xfe,  0xc0,  0x5a,  0xb7,  0xfe,  0x00,  0xcd,  0xfe,  0x01,  0xcc,  0xfe,  0x4a,  0x46,  0xe4,
+  0x9a,  0x7f,  0x05,  0x10,  0xfe,  0x2e,  0x13,  0x5a,  0x5c,  0xfe,  0x4d,  0xf4,  0x1e,  0xe2,  0x0f,  0x5e,
+  0x01,  0x9f,  0xad,  0xfe,  0x40,  0x4c,  0xfe,  0xc5,  0x58,  0x01,  0x47,  0xfe,  0x00,  0x07,  0x7f,  0x05,
+  0x10,  0x87,  0x5a,  0x8e,  0xfe,  0x05,  0x57,  0xfe,  0x08,  0x10,  0xfe,  0x45,  0x58,  0x01,  0x47,  0xfe,
+  0x8d,  0x56,  0xbe,  0xfe,  0x80,  0x4c,  0xfe,  0x05,  0x17,  0x03,  0x09,  0x10,  0x75,  0x6d,  0xfe,  0x60,
+  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xe3,  0x39,  0x9e,  0xfe,  0xc4,  0x16,
+  0x01,  0xfe,  0xca,  0x17,  0xd9,  0x8a,  0x39,  0x6d,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xbf,
+  0x28,  0xfe,  0xb4,  0x16,  0xfe,  0xda,  0x10,  0x09,  0x10,  0x75,  0x04,  0xfe,  0x64,  0x01,  0xfe,  0x00,
+  0xf4,  0x22,  0xfe,  0x18,  0x58,  0x04,  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0x8a,  0x22,  0xfe,  0x3c,
+  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x6d,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,
+  0x1c,  0xf7,  0x22,  0x9e,  0xfe,  0x0e,  0x17,  0xfe,  0xb6,  0x14,  0x30,  0x03,  0xbf,  0x28,  0xfe,  0xe6,
+  0x16,  0xfe,  0x9c,  0x10,  0x09,  0x10,  0x75,  0xbe,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xdf,  0xe3,  0x31,
+  0x9e,  0xfe,  0x30,  0x17,  0xfe,  0x94,  0x14,  0x2e,  0x8a,  0x31,  0x6d,  0x1d,  0xfe,  0xaf,  0x19,  0xfe,
+  0x98,  0xe7,  0x00,  0x03,  0xbf,  0x28,  0xfe,  0x24,  0x17,  0xfe,  0x6c,  0x10,  0x09,  0x10,  0x75,  0xfe,
+  0x30,  0xbc,  0xfe,  0xb2,  0xbc,  0x8a,  0xe0,  0x6d,  0x1d,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xe0,
+  0x9e,  0xfe,  0x68,  0x17,  0xfe,  0x5c,  0x14,  0x30,  0x03,  0xbf,  0x28,  0xfe,  0x54,  0x17,  0xfe,  0x42,
+  0x10,  0xfe,  0x02,  0xf6,  0x10,  0x75,  0xfe,  0x18,  0xfe,  0x65,  0xfe,  0x19,  0xfe,  0x66,  0xd0,  0xe3,
+  0x78,  0x9e,  0xfe,  0x8e,  0x17,  0xfe,  0x36,  0x14,  0xe2,  0x8a,  0x78,  0x46,  0xfe,  0x83,  0x58,  0xfe,
+  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x6b,  0x33,
+  0x03,  0x6b,  0x33,  0xfe,  0x12,  0x45,  0x28,  0xfe,  0x7e,  0x17,  0x17,  0x06,  0x4b,  0xfb,  0xe5,  0x02,
+  0x27,  0xfe,  0x39,  0xf0,  0xfe,  0xd2,  0x17,  0x24,  0x03,  0xfe,  0x7e,  0x18,  0x1b,  0x18,  0x85,  0x07,
+  0x0d,  0x03,  0x75,  0x04,  0xe7,  0x1b,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x1c,  0x0f,  0x1e,
+  0x01,  0x15,  0x05,  0x10,  0x4e,  0x4c,  0xfe,  0x78,  0x14,  0xfe,  0x34,  0x12,  0x58,  0x89,  0x37,  0x39,
+  0xc6,  0xfe,  0xe9,  0x13,  0x1c,  0x0f,  0x3d,  0x01,  0x15,  0x05,  0x10,  0x4e,  0x4c,  0xfe,  0x56,  0x14,
+  0xb0,  0x58,  0x89,  0x37,  0x39,  0xc6,  0xfe,  0xe9,  0x13,  0x09,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,
+  0x13,  0xfe,  0x15,  0x00,  0x97,  0xa3,  0x33,  0x01,  0xfe,  0xf8,  0x0e,  0x09,  0x06,  0x03,  0x0a,  0x4f,
+  0x39,  0x3a,  0x07,  0x3d,  0x09,  0xa1,  0x01,  0x40,  0x11,  0x48,  0x07,  0x1e,  0x09,  0x51,  0x01,  0x79,
+  0x09,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x36,  0xfe,  0xa8,  0x00,  0x21,  0x7b,  0xfe,
+  0x48,  0x55,  0x30,  0xfe,  0xc9,  0x55,  0x03,  0x2a,  0xc4,  0x72,  0x16,  0xc4,  0x03,  0x0f,  0xc7,  0x01,
+  0x15,  0xed,  0x0f,  0x7e,  0x01,  0x15,  0xfe,  0x49,  0x44,  0x28,  0xfe,  0xc8,  0x18,  0x0f,  0x1e,  0x01,
+  0x15,  0x05,  0x10,  0x4e,  0x0f,  0x5e,  0x01,  0xc5,  0x0f,  0x7e,  0x01,  0x15,  0x72,  0x7f,  0x03,  0xfe,
+  0x40,  0x5e,  0xfe,  0xe2,  0x08,  0xfe,  0xc0,  0x4c,  0x2a,  0x3c,  0x05,  0x10,  0xfe,  0x52,  0x12,  0x4c,
+  0x05,  0x00,  0xfe,  0x18,  0x12,  0xfe,  0xe1,  0x18,  0xfe,  0x19,  0xf4,  0xfe,  0x7f,  0x00,  0x2e,  0xfe,
+  0xe2,  0x08,  0x72,  0x4c,  0x3e,  0x05,  0x7b,  0xa7,  0xfe,  0x82,  0x48,  0xfe,  0x01,  0x80,  0xfe,  0xd7,
+  0x10,  0xfe,  0xc4,  0x48,  0x07,  0x2d,  0x09,  0x3c,  0xfe,  0x40,  0x5f,  0x1c,  0x01,  0x40,  0x11,  0xfe,
+  0xdd,  0x00,  0xfe,  0x14,  0x46,  0x07,  0x2d,  0x09,  0x3c,  0x01,  0x40,  0x11,  0xfe,  0xdd,  0x00,  0xfe,
+  0x40,  0x4a,  0x70,  0xfe,  0x06,  0x17,  0xfe,  0x01,  0x07,  0xfe,  0x82,  0x48,  0xfe,  0x04,  0x17,  0x03,
+  0xf0,  0x18,  0x77,  0xfe,  0x50,  0x19,  0x04,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,
+  0xf0,  0xd5,  0x77,  0xfe,  0x62,  0x19,  0x04,  0xfe,  0x92,  0x00,  0xcf,  0x1d,  0xdf,  0xf0,  0xfe,  0x0b,
+  0x00,  0x77,  0xfe,  0x74,  0x19,  0x04,  0xfe,  0x94,  0x00,  0xcf,  0x22,  0xfe,  0x08,  0x10,  0x04,  0xfe,
+  0x96,  0x00,  0xcf,  0x88,  0xfe,  0x4e,  0x45,  0xd8,  0xfe,  0x0a,  0x45,  0xff,  0x04,  0x68,  0x54,  0xfe,
+  0xf1,  0x10,  0x1b,  0x8b,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,
+  0xfe,  0x00,  0x04,  0xd8,  0xfe,  0x48,  0xf4,  0x18,  0x96,  0xfe,  0xa8,  0x19,  0x07,  0x18,  0x03,  0x05,
+  0xa5,  0xfe,  0x5a,  0xf0,  0xfe,  0xb8,  0x19,  0x20,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x05,  0x1d,
+  0xfe,  0x5a,  0xf0,  0xfe,  0xc6,  0x19,  0x20,  0xd6,  0xfe,  0x26,  0x10,  0x05,  0x18,  0x85,  0x20,  0x88,
+  0xdf,  0x05,  0x0b,  0x85,  0x20,  0xae,  0xfe,  0x0e,  0x10,  0x05,  0x06,  0x85,  0x20,  0x5d,  0xce,  0xb5,
+  0x03,  0x17,  0xfe,  0x09,  0x00,  0x01,  0x2e,  0x2f,  0xfe,  0xf6,  0x19,  0x04,  0x74,  0xb7,  0x03,  0x19,
+  0xfe,  0x16,  0x1a,  0xfe,  0x14,  0xf0,  0x0c,  0x2f,  0xfe,  0x0a,  0x1a,  0x19,  0xfe,  0x16,  0x1a,  0xfe,
+  0x82,  0xf0,  0xfe,  0x0e,  0x1a,  0x03,  0xff,  0x34,  0x00,  0x00,};
+
+STATIC unsigned short _adv_asc38C0800_size =
+    sizeof(_adv_asc38C0800_buf); /* 0x14AA */
+STATIC unsigned long _adv_asc38C0800_chksum =
+    0x05297A65UL; /* Expanded checksum. */
 
 /* a_init.c */
 /*
@@ -14021,8 +15382,8 @@
  * Additional structure information can be found in a_condor.h where
  * the structure is defined.
  */
-STATIC ADVEEP_CONFIG
-Default_EEPROM_Config ASC_INITDATA = {
+STATIC ADVEEP_3550_CONFIG
+Default_3550_EEPROM_Config ASC_INITDATA = {
     ADV_EEPROM_BIOS_ENABLE,     /* cfg_msw */
     0x0000,                     /* cfg_lsw */
     0xFFFF,                     /* disc_enable */
@@ -14038,7 +15399,7 @@
     0,                          /* bios_id_lun */
     0,                          /* termination */
     0,                          /* reserved1 */
-    0xFFEF,                     /* bios_ctrl */
+    0xFFE7,                     /* bios_ctrl */
     0xFFFF,                     /* ultra_able */
     0,                          /* reserved2 */
     ASC_DEF_MAX_HOST_QNG,       /* max_host_qng */
@@ -14059,6 +15420,71 @@
     0                           /* num_of_err */
 };
 
+STATIC ADVEEP_38C0800_CONFIG
+Default_38C0800_EEPROM_Config ASC_INITDATA = {
+    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_msw */
+    0x0000,                     /* 01 cfg_lsw */
+    0xFFFF,                     /* 02 disc_enable */
+    0xFFFF,                     /* 03 wdtr_able */
+    0x4444,                     /* 04 sdtr_speed1 */
+    0xFFFF,                     /* 05 start_motor */
+    0xFFFF,                     /* 06 tagqng_able */
+    0xFFFF,                     /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    7,                          /* 09 adapter_scsi_id */
+    0,                          /*    bios_boot_delay */
+    3,                          /* 10 scsi_reset_delay */
+    0,                          /*    bios_id_lun */
+    0,                          /* 11 termination_se */
+    0,                          /*    termination_lvd */
+    0xFFE7,                     /* 12 bios_ctrl */
+    0x4444,                     /* 13 sdtr_speed2 */
+    0x4444,                     /* 14 sdtr_speed3 */
+    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0x4444,                     /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    ADV_PCI_VENDOR_ID,          /* 58 subsysvid */
+    ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
 /*
  * Initialize the ADV_DVC_VAR structure.
  *
@@ -14067,8 +15493,10 @@
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-int ASC_INIT
+ASC_INITFUNC(
+STATIC int,
 AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+)
 {
     ushort      warn_code;
     AdvPortAddr iop_base;
@@ -14119,8 +15547,8 @@
     /*
      * Save the state of the PCI Configuration Command Register
      * "Parity Error Response Control" Bit. If the bit is clear (0),
-     * in AdvInitAsc3550Driver() tell the microcode to ignore DMA
-     * parity errors.
+     * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+     * DMA parity errors.
      */
     asc_dvc->cfg->control_flag = 0;
     if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
@@ -14129,13 +15557,19 @@
         asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
     }
 
-    asc_dvc->cur_host_qng = 0;
-
     asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
       ADV_LIB_VERSION_MINOR;
     asc_dvc->cfg->chip_version =
       AdvGetChipVersion(iop_base, asc_dvc->bus_type);
 
+    ASC_DBG2(1, "iopb_chip_id_1: %x %x\n",
+        (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+        (ushort) ADV_CHIP_ID_BYTE);
+
+    ASC_DBG2(1, "iopw_chip_id_0: %x %x\n",
+        (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+        (ushort) ADV_CHIP_ID_WORD);
+
     /*
      * Reset the chip to start and allow register writes.
      */
@@ -14145,37 +15579,54 @@
         return ADV_ERROR;
     }
     else {
-
-        AdvResetChip(asc_dvc);
-
-        if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR)
+        /*
+         * The caller must set 'chip_type' to a valid setting.
+         */
+        if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+            asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+            asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
         {
+            asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
             return ADV_ERROR;
         }
-        warn_code |= status;
 
         /*
-         * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-         * Resets should be performed.
+         * Reset Chip.
          */
-        if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+            ADV_CTRL_REG_CMD_RESET);
+        DvcSleepMilliSecond(100);
+        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+            ADV_CTRL_REG_CMD_WR_IO_REG);
+
+        if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+        {
+            if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
+        } else
         {
-            AdvResetSCSIBus(asc_dvc);
+            if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
         }
+        warn_code |= status;
     }
 
     return warn_code;
 }
 
 /*
- * Initialize the ASC3550.
+ * Initialize the ASC-3550.
  *
  * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
  *
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-int ASC_INIT
+STATIC int
 AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
 {
     AdvPortAddr iop_base;
@@ -14183,12 +15634,20 @@
     ulong       sum;
     int         begin_addr;
     int         end_addr;
-    int         code_sum;
+    ushort      code_sum;
     int         word;
-    int         rql_addr;                   /* RISC Queue List address */
+    int         j;
+    int         adv_asc3550_expanded_size;
+    ADV_CARR_T  *carrp;
+    ulong       contig_len;
+    long        buf_size;
+    ulong       carr_paddr;
     int         i;
     ushort      scsi_cfg1;
-    uchar       biosmem[ASC_MC_BIOSLEN];    /* BIOS RISC Memory 0x40-0x8F. */
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able = 0, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
 
     /* If there is already an error, don't continue. */
     if (asc_dvc->err_code != 0)
@@ -14196,6 +15655,15 @@
         return ADV_ERROR;
     }
 
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC3550)
+    {
+        asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
     warn_code = 0;
     iop_base = asc_dvc->iop_base;
 
@@ -14207,9 +15675,36 @@
      * Note: This code makes the assumption, which is currently true,
      * that a chip reset does not clear RISC LRAM.
      */
-    for (i = 0; i < ASC_MC_BIOSLEN; i++)
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+    {
+        ushort  bios_version, major, minor;
+
+        bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
+        major = (bios_version  >> 12) & 0xF;
+        minor = (bios_version  >> 8) & 0xF;
+        if (major <= 3 || (major == 3 && minor == 1))
+        {
+            /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+            AdvReadWordLram(iop_base, 0x120, wdtr_able);
+        } else
+        {
+            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+        }
+    }
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
     {
-        AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
     }
 
     /*
@@ -14218,16 +15713,58 @@
      * Write the microcode image to RISC memory starting at address 0.
      */
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-    for (word = 0; word < _adv_mcode_size; word += 2)
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc3550_size; i++)
     {
-        AdvWriteWordAutoIncLram(iop_base,
-            *((ushort *) (&_adv_mcode_buf[word])));
+        if (_adv_asc3550_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base,
+                    *((ushort *) (&_adv_asc3550_buf[i + 2])));
+                word++;
+            }
+           i += 3;
+        } else if (_adv_asc3550_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base,
+                *((ushort *) (&_adv_asc3550_buf[i + 1])));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base,
+                *((ushort *) &_adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+            word++;
+        }
     }
 
     /*
-     * Clear the rest of Condor's Internal RAM (8KB).
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc3550_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-3550 Internal RAM (8KB).
      */
-    for (; word < ADV_CONDOR_MEMSIZE; word += 2)
+    for (; word < ADV_3550_MEMSIZE; word += 2)
     {
         AdvWriteWordAutoIncLram(iop_base, 0);
     }
@@ -14237,12 +15774,13 @@
      */
     sum = 0;
     AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-    for (word = 0; word < _adv_mcode_size; word += 2)
+
+    for (word = 0; word < adv_asc3550_expanded_size; word += 2)
     {
         sum += AdvReadWordAutoIncLram(iop_base);
     }
 
-    if (sum != _adv_mcode_chksum)
+    if (sum != _adv_asc3550_chksum)
     {
         asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
         return ADV_ERROR;
@@ -14251,35 +15789,35 @@
     /*
      * Restore the RISC memory BIOS region.
      */
-    for (i = 0; i < ASC_MC_BIOSLEN; i++)
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
     {
-        AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+        AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
     }
 
     /*
      * Calculate and write the microcode code checksum to the microcode
-     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).  
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
      */
     AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
     AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
     code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
     for (word = begin_addr; word < end_addr; word += 2)
     {
-        code_sum += *((ushort *) (&_adv_mcode_buf[word]));
+        code_sum += AdvReadWordAutoIncLram(iop_base);
     }
     AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
     /*
-     * Read microcode version and date.
+     * Read and save microcode version and date.
      */
     AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
     AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
 
     /*
-     * Initialize microcode operating variables
+     * Set the chip type to indicate the ASC3550.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID,
-                       asc_dvc->chip_scsi_id);
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
 
     /*
      * If the PCI Configuration Command Register "Parity Error Response
@@ -14289,7 +15827,7 @@
      */
     if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
     {
-        /* 
+        /*
          * Note: Don't remove the use of a temporary variable in
          * the following code, otherwise the Microsoft C compiler
          * will turn the following lines into a no-op.
@@ -14300,27 +15838,86 @@
     }
 
     /*
-     * Set default microcode operating variables for WDTR, SDTR, and
-     * command tag queuing based on the EEPROM configuration values.
+     * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+     * threshold of 128 bytes. This register is only accessible to the host.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        START_CTL_EMFU | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
      *
-     * These ADV_DVC_VAR fields and the microcode variables will be
-     * changed in AdvInquiryHandling() if it is found a device is
-     * incapable of a particular feature.
+     * If SCSI Bus Resets haev been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
      */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
 
     /*
-     * Set the microcode ULTRA target mask from EEPROM value. The
-     * SDTR target mask overrides the ULTRA target mask in the
-     * microcode so it is safe to set this value without determining
-     * whether the device supports SDTR.
-     * 
-     * Note: There is no way to know whether a device supports ULTRA
-     * speed without attempting a SDTR ULTRA speed negotiation with
-     * the device. The device will reject the speed if it does not
-     * support it by responding with an SDTR message containing a
-     * slower speed.
+     * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+     * bitmask. These values determine the maximum SDTR speed negotiated
+     * with a device.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     *
+     * 4-bit speed  SDTR speed name
+     * ===========  ===============
+     * 0000b (0x0)  SDTR disabled
+     * 0001b (0x1)  5 Mhz
+     * 0010b (0x2)  10 Mhz
+     * 0011b (0x3)  20 Mhz (Ultra)
+     * 0100b (0x4)  40 Mhz (LVD/Ultra2)
+     * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
+     * 0110b (0x6)  Undefined
+     * .
+     * 1111b (0xF)  Undefined
+     */
+    word = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
+        {
+            /* Set Ultra speed for TID 'tid'. */
+            word |= (0x3 << (4 * (tid % 4)));
+        } else
+        {
+            /* Set Fast speed for TID 'tid'. */
+            word |= (0x2 << (4 * (tid % 4)));
+        }
+        if (tid == 3) /* Check if done with sdtr_speed1. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+            word = 0;
+        } else if (tid == 7) /* Check if done with sdtr_speed2. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+            word = 0;
+        } else if (tid == 11) /* Check if done with sdtr_speed3. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+            word = 0;
+        } else if (tid == 15) /* Check if done with sdtr_speed4. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+            /* End of loop. */
+        }
+    }
+
+    /*
+     * Set microcode operating variable for the disconnect per TID bitmask.
      */
-    AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able);
     AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
 
 
@@ -14332,7 +15929,7 @@
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
         PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
-  
+
     /*
      * Determine SCSI_CFG1 Microcode Default Value.
      *
@@ -14349,8 +15946,8 @@
     if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
         (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
     {
-        asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
-        return ADV_ERROR;
+            asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+            return ADV_ERROR;
     }
 
     /*
@@ -14379,7 +15976,7 @@
      * termination value based on a table listed in a_condor.h.
      *
      * If manual termination was specified with an EEPROM setting
-     * then 'termination' was set-up in AdvInitFromEEP() and
+     * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
      * is ready to be 'ored' into SCSI_CFG1.
      */
     if (asc_dvc->cfg->termination == 0)
@@ -14431,7 +16028,21 @@
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
-                       FLTR_11_TO_20NS | scsi_cfg1);
+        FLTR_11_TO_20NS | scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-3550 has 8KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_8KB);
 
     /*
      * Set SEL_MASK Microcode Default Value
@@ -14440,59 +16051,1007 @@
      * after it is started below.
      */
     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-                        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
     /*
-     * Link all the RISC Queue Lists together in a doubly-linked
-     * NULL terminated list.
+     * Build carrier freelist.
      *
-     * Skip the NULL (0) queue which is not used.
+     * Driver must have already allocated memory and set 'carrier_buf'.
      */
-    for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE;
-         i < ASC_MC_RISC_Q_TOTAL_CNT;
-         i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE)
+    ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
     {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address of the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = (ulong) carrp;
+
         /*
-         * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers
-         * in a one word write and set the state (RQL_STATE) to free.
+         * Insert the carrier at the beginning of the freelist.
          */
-        AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8)));
-        AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+        carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
     }
+    while (buf_size > 0);
 
     /*
-     * Set the Host and RISC Queue List pointers.
-     *
-     * Both sets of pointers are initialized with the same values:
-     * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF).
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
      */
-    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST);
-    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST);
 
-    AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST);
-    AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
 
     /*
-     * Finally, set up the last RISC Queue List (255) with
-     * a NULL forward pointer.
+     * The first command issued will be placed in the stopper carrier.
      */
-    AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8)));
-    AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+    asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
 
-    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-         (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+    /*
+     * Set RISC ICQ physical address start value.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
 
-    /* 
-     * Note: Don't remove the use of a temporary variable in
-     * the following code, otherwise the Microsoft C compiler
-     * will turn the following lines into a no-op.
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
      */
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Set RISC IRQ physical address start value.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+
+    /*
+     * Note: Don't remove the use of a temporary variable in
+     * the following code, otherwise the Microsoft C compiler
+     * will turn the following lines into a no-op.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC-38C0800.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+STATIC int
+AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ulong       sum;
+    int         begin_addr;
+    int         end_addr;
+    ushort      code_sum;
+    int         word;
+    int         j;
+    int         adv_asc38C0800_expanded_size;
+    ADV_CARR_T  *carrp;
+    ulong       contig_len;
+    long        buf_size;
+    ulong       carr_paddr;
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       byte;
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * RAM BIST (RAM Built-In Self Test)
+     *
+     * Address : I/O base + offset 0x38h register (byte).
+     * Function: Bit 7-6(RW) : RAM mode
+     *                          Normal Mode   : 0x00
+     *                          Pre-test Mode : 0x40
+     *                          RAM Test Mode : 0x80
+     *           Bit 5       : unused
+     *           Bit 4(RO)   : Done bit
+     *           Bit 3-0(RO) : Status
+     *                          Host Error    : 0x08
+     *                          Int_RAM Error : 0x04
+     *                          RISC Error    : 0x02
+     *                          SCSI Error    : 0x01
+     *                          No Error      : 0x00
+     *
+     * Note: RAM BIST code should be put right here, before loading the
+     * microcode and after saving the RISC memory BIOS region.
+     */
+
+    /*
+     * LRAM Pre-test
+     *
+     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+     * to NORMAL_MODE, return an error too.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+            != NORMAL_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+    }
+
+    /*
+     * LRAM Test - It takes about 1.5 ms to run through the test.
+     *
+     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+     * If Done bit not set or Status not 0, save register byte, set the
+     * err_code, and return an error.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+
+    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
+    {
+        /* Get here if Done bit not set or Status not 0. */
+        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+        return ADV_ERROR;
+    }
+
+    /* We need to reset back to normal mode after LRAM test passes. */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     *
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
+    {
+        if (_adv_asc38C0800_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base,
+                    *((ushort *) (&_adv_asc38C0800_buf[i + 2])));
+                word++;
+            }
+           i += 3;
+        } else if (_adv_asc38C0800_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base,
+                *((ushort *) (&_adv_asc38C0800_buf[i + 1])));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base, *((ushort *)
+                &_adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+            word++;
+        }
+    }
+
+    /*
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc38C0800_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+     */
+    for (; word < ADV_38C0800_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+
+    if (sum != _adv_asc38C0800_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Set the chip type to indicate the ASC38C0800.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+    /*
+     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+     * cable detection and then we are able to read C_DET[3:0].
+     *
+     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+     * Microcode Default Value' section below.
+     */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        /*
+         * Note: Don't remove the use of a temporary variable in
+         * the following code, otherwise the Microsoft C compiler
+         * will turn the following lines into a no-op.
+         */
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+     * bits for the default FIFO threshold.
+     *
+     * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+     *
+     * For DMA Errata #4 set the BC_THRESH_ENB bit.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
+     *
+     * If SCSI Bus Resets have been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
+
+    /*
+     * Set microcode operating variables for DISC and SDTR_SPEED1,
+     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+     * configuration values.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+
+    /*
+     * Determine SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+
+    /* Read current SCSI_CFG1 Register value. */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If the internal narrow cable is reversed all of the SCSI_CTRL
+     * register signals will be set. Check for and return an error if
+     * this condition is found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * All kind of combinations of devices attached to one of four connectors
+     * are acceptable except HVD device attached. For example, LVD device can
+     * be attached to SE connector while SE device attached to LVD connector.
+     * If LVD device attached to SE connector, it only runs up to Ultra speed.
+     *
+     * If an HVD device is attached to one of LVD connectors, return an error.
+     * However, there is no way to detect HVD device attached to SE connectors.
+     */
+    if (scsi_cfg1 & HVD)
+    {
+        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If either SE or LVD automatic termination control is enabled, then
+     * set the termination value based on a table listed in a_condor.h.
+     *
+     * If manual termination was specified with an EEPROM setting then
+     * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+     * be 'ored' into SCSI_CFG1.
+     */
+    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
+    {
+        /* SE automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_SE)
+        {
+            /* TERM_SE_HI: on, TERM_SE_LO: on */
+            case 0x1: case 0x2: case 0x3:
+                asc_dvc->cfg->termination |= TERM_SE;
+                break;
+
+            /* TERM_SE_HI: on, TERM_SE_LO: off */
+            case 0x0:
+                asc_dvc->cfg->termination |= TERM_SE_HI;
+                break;
+        }
+    }
+
+    if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
+    {
+        /* LVD automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_LVD)
+        {
+            /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+            case 0x4: case 0x8: case 0xC:
+                asc_dvc->cfg->termination |= TERM_LVD;
+                break;
+
+            /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+            case 0x0:
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_SE and TERM_LVD bits.
+     */
+    scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+
+    /*
+     * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+     */
+    scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+
+    /*
+     * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+     * and set possibly modified termination control bits in the Microcode
+     * SCSI_CFG1 Register Value.
+     */
+    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set possibly modified termination control and reset DIS_TERM_DRV
+     * bits in the Microcode SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-38C0800 has 16KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_16KB);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Build the carrier freelist.
+     *
+     * Driver must have already allocated memory and set 'carrier_buf'.
+     */
+
+    ADV_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+    {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address for the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (long *) &contig_len, ADV_IS_CARRIER_FLAG);
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = (ulong) carrp;
+
+        /*
+         * Insert the carrier at the beginning of the freelist.
+         */
+        carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
+    }
+    while (buf_size > 0);
+
+    /*
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->icq_sp->next_vpa;
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Set RISC ICQ physical address start value.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) asc_dvc->irq_sp->next_vpa;
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Set RISC IRQ physical address start value.
+     */
+    AdvWriteDWordLram(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+    /*
+     * Note: Don't remove the use of a temporary variable in
+     * the following code, otherwise the Microsoft C compiler
+     * will turn the following lines into a no-op.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+)
+{
+    AdvPortAddr              iop_base;
+    ushort                   warn_code;
+    ADVEEP_38C0800_CONFIG    eep_config;
+    int                      i;
+    uchar                    tid, termination;
+    ushort                   sdtr_speed = 0;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+        {
+            *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_38C0800_EEPROM_Config + i);
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+
+        AdvSet38C0800EEPConfig(iop_base, &eep_config);
+    }
+    /*
+     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+    /*
+     * For every Target ID if any of its 'sdtr_speed[1234]' bits
+     * are set, then set an 'sdtr_able' bit for it.
+     */
+    asc_dvc->sdtr_able = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (tid == 0)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed1;
+        } else if (tid == 4)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed2;
+        } else if (tid == 8)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed3;
+        } else if (tid == 12)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed4;
+        }
+        if (sdtr_speed & ADV_MAX_TID)
+        {
+            asc_dvc->sdtr_able |= (1 << tid);
+        }
+        sdtr_speed >>= 4;
+    }
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ADV_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ADV_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination_se == 0)
+    {
+        termination = 0;                         /* auto termination for SE */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_se == 1)
+        {
+            termination = 0;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_se == 2)
+        {
+            termination = TERM_SE_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_se == 3)
+        {
+            termination = TERM_SE;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_se' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    if (eep_config.termination_lvd == 0)
+    {
+        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_lvd == 1)
+        {
+            asc_dvc->cfg->termination = termination;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_lvd == 2)
+        {
+            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_lvd == 3)
+        {
+            asc_dvc->cfg->termination =
+                termination | TERM_LVD;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_lvd' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            asc_dvc->cfg->termination = termination;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
 
-    /* finally, finally, gentlemen, start your engine */
-    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
- 
     return warn_code;
 }
 
@@ -14508,12 +17067,14 @@
  *
  * Note: Chip is stopped on entry.
  */
-STATIC int ASC_INIT
-AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
+ASC_INITFUNC(
+STATIC int,
+AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+)
 {
     AdvPortAddr         iop_base;
     ushort              warn_code;
-    ADVEEP_CONFIG       eep_config;
+    ADVEEP_3550_CONFIG  eep_config;
     int                 i;
 
     iop_base = asc_dvc->iop_base;
@@ -14525,17 +17086,17 @@
      *
      * Set default values if a bad checksum is found.
      */
-    if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
     {
         warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
         /*
          * Set EEPROM default values.
          */
-        for (i = 0; i < sizeof(ADVEEP_CONFIG); i++)
+        for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
         {
             *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_EEPROM_Config + i);
+                *((uchar *) &Default_3550_EEPROM_Config + i);
         }
 
         /*
@@ -14545,15 +17106,17 @@
          */
         eep_config.serial_number_word3 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+
         eep_config.serial_number_word2 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+
         eep_config.serial_number_word1 =
             AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
-        AdvSetEEPConfig(iop_base, &eep_config);
-    }
 
+        AdvSet3550EEPConfig(iop_base, &eep_config);
+    }
     /*
-     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
      * EEPROM configuration that was read.
      *
      * This is the mapping of EEPROM fields to Adv Library fields.
@@ -14568,7 +17131,6 @@
     asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
     asc_dvc->start_motor = eep_config.start_motor;
     asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-    asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay;
     asc_dvc->bios_ctrl = eep_config.bios_ctrl;
     asc_dvc->no_scam = eep_config.scam_tolerant;
     asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
@@ -14619,7 +17181,7 @@
     }
 
     /*
-     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng'
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
      * values based on possibly adjusted EEPROM values.
      */
     asc_dvc->max_host_qng = eep_config.max_host_qng;
@@ -14672,8 +17234,48 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-STATIC ushort ASC_INIT
-AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
+)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
+         eep_addr < ASC_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval;
+        *wbuf = wval;
+    }
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++;
+    for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
+         eep_addr < ASC_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    }
+    return chksum;
+}
+
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+ASC_INITFUNC(
+STATIC ushort,
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+)
 {
     ushort              wval, chksum;
     ushort              *wbuf;
@@ -14704,8 +17306,10 @@
 /*
  * Read the EEPROM from specified location
  */
-STATIC ushort ASC_INIT
+ASC_INITFUNC(
+STATIC ushort,
 AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+)
 {
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
         ASC_EEP_CMD_READ | eep_word_addr);
@@ -14716,8 +17320,10 @@
 /*
  * Wait for EEPROM command to complete
  */
-STATIC void ASC_INIT
+ASC_INITFUNC(
+STATIC void,
 AdvWaitEEPCmd(AdvPortAddr iop_base)
+)
 {
     int eep_delay_ms;
 
@@ -14739,11 +17345,63 @@
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
-STATIC void ASC_INIT
-AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+void
+AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+    ushort *wbuf;
+    ushort addr, chksum;
+
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 20
+     */
+    for (addr = ASC_EEP_DVC_CFG_BEGIN;
+         addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        chksum += *wbuf;
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 21
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++;        /* skip over check_sum */
+
+    /*
+     * Write EEPROM OEM name at words 22 to 29
+     */
+    for (addr = ASC_EEP_DVC_CTL_BEGIN;
+         addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
 {
-    ushort       *wbuf;
-    ushort       addr, chksum;
+    ushort *wbuf;
+    ushort addr, chksum;
 
     wbuf = (ushort *) cfg_buf;
     chksum = 0;
@@ -14752,7 +17410,7 @@
     AdvWaitEEPCmd(iop_base);
 
     /*
-     * Write EEPROM from word 0 to word 15
+     * Write EEPROM from word 0 to word 20
      */
     for (addr = ASC_EEP_DVC_CFG_BEGIN;
          addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
@@ -14765,7 +17423,7 @@
     }
 
     /*
-     * Write EEPROM checksum at word 18
+     * Write EEPROM checksum at word 21
      */
     AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
     AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
@@ -14773,7 +17431,7 @@
     wbuf++;        /* skip over check_sum */
 
     /*
-     * Write EEPROM OEM name at words 19 to 26 
+     * Write EEPROM OEM name at words 22 to 29
      */
     for (addr = ASC_EEP_DVC_CTL_BEGIN;
          addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
@@ -14787,138 +17445,261 @@
     return;
 }
 
+/* a_advlib.c */
 /*
- * This function resets the chip and SCSI bus
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
  *
- * It is up to the caller to add a delay to let the bus settle after
- * calling this function.
+ *   Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ *   add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ *   RISC to notify it a new command is ready to be executed.
  *
- * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in
- * AdvInitAsc3550Driver(). Here when doing a write to one of these
- * registers read first and then write.
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
  *
- * Note: A SCSI Bus Reset can not be done until after the EEPROM
- * configuration is read to determine whether SCSI Bus Resets
- * should be performed.
+ * Return:
+ *      ADV_SUCCESS(1) - The request was successfully queued.
+ *      ADV_BUSY(0) -    Resource unavailable; Retry again after pending
+ *                       request completes.
+ *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
+ *                       host IC error.
  */
-STATIC void ASC_INIT
-AdvResetChip(ADV_DVC_VAR *asc_dvc)
+STATIC int
+AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
+                ADV_SCSI_REQ_Q *scsiq)
 {
-    AdvPortAddr    iop_base;
-    ushort         word;
-    uchar          byte;
+    int                    last_int_level;
+    AdvPortAddr            iop_base;
+    long                   req_size;
+    ulong                  req_paddr;
+    ADV_CARR_T             *new_carrp;
+
+    ADV_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+
+    /*
+     * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+     */
+    if (scsiq->target_id > ADV_MAX_TID)
+    {
+        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+        scsiq->done_status = QD_WITH_ERROR;
+        return ADV_ERROR;
+    }
 
     iop_base = asc_dvc->iop_base;
 
+    last_int_level = DvcEnterCritical();
+
     /*
-     * Reset Chip.
+     * Allocate a carrier ensuring at least one carrier always
+     * remains on the freelist and initialize fields.
      */
-    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
-    DvcSleepMilliSecond(100);
-    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+    if ((new_carrp = asc_dvc->carr_freelist) == NULL)
+    {
+       return ADV_BUSY;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *) new_carrp->next_vpa;
+    asc_dvc->carr_pending_cnt++;
 
     /*
-     * Initialize Chip registers.
-     * 
-     * Note: Don't remove the use of a temporary variable in the following
-     * code, otherwise the Microsoft C compiler will turn the following lines
-     * into a no-op.
+     * Set the carrier to be a stopper by setting 'next_vpa'
+     * to the stopper value. The current stopper will be changed
+     * below to point to the new stopper.
+     */
+    new_carrp->next_vpa = ASC_CQ_STOPPER;
+
+    /*
+     * Clear the ADV_SCSI_REQ_Q done flag.
      */
-    byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG);
-    byte |= RAM_SZ_8KB;
-    AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte);
+    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+    req_size = sizeof(ADV_SCSI_REQ_Q);
+    req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
+        (long *) &req_size, ADV_IS_SCSIQ_FLAG);
+
+    ADV_ASSERT(ADV_DWALIGN(req_paddr) == req_paddr);
+    ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+    /* Save virtual and physical address of ADV_SCSI_REQ_Q and Carrier. */
+    scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
+    scsiq->scsiq_rptr = req_paddr;
 
-    word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-    word &= ~BIG_ENDIAN;
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word);
+    /* XXX - Could have the RISC set these values. */
+    scsiq->carr_va = (ulong) asc_dvc->icq_sp;
+    scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
+
+   /*
+    * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+    * the microcode. The newly allocated stopper will become the new
+    * stopper.
+    */
+    asc_dvc->icq_sp->areq_vpa = (ulong) req_paddr;
 
     /*
-     * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold
-     * of 128 bytes. This register is only accessible to the host.
+     * Set the 'next_vpa' pointer for the old stopper to be the
+     * physical address of the new stopper. The RISC can only
+     * follow physical addresses.
      */
-    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        START_CTL_EMFU | READ_CMD_MRM);
-}
+    asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
 
-/* a_advlib.c */
-/*
- * Description:
- *      Send a SCSI request to the ASC3550 chip
- *
- * If there is no SG list for the request, set 'sg_entry_cnt' to 0.
- *
- * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be
- * called. It is assumed the caller has already initialized 'sg_real_addr'.
- *
- * Return:
- *      ADV_SUCCESS(1) - the request is in the mailbox
- *      ADV_BUSY(0) - total request count > 253, try later
- *      ADV_ERROR(-1) - invalid scsi request Q
- */
-STATIC int
-AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
-                ADV_SCSI_REQ_Q *scsiq)
-{
-    if (scsiq == (ADV_SCSI_REQ_Q *) 0L)
+    /*
+     * Set the host adapter stopper pointer to point to the new carrier.
+     */
+    asc_dvc->icq_sp = new_carrp;
+
+    /*
+     * Tickle the RISC to tell it to read its Command Queue Head pointer.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
     {
-        /* 'scsiq' should never be NULL. */
-        ADV_ASSERT(0);
-        return ADV_ERROR;
+        /*
+         * Clear the tickle value. In the ASC-3550 the RISC flag
+         * command 'clr_tickle_a' does not work unless the host
+         * value is cleared.
+         */
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
     }
 
-    return AdvSendScsiCmd(asc_dvc, scsiq);
+    DvcLeaveCritical(last_int_level);
+
+    return ADV_SUCCESS;
 }
 
 /*
  * Reset SCSI Bus and purge all outstanding requests.
  *
  * Return Value:
- *      ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
- *
- * Note: Should always return ADV_TRUE.
+ *      ADV_TRUE(1) -   All requests are purged and SCSI Bus is reset.
+ *      ADV_FALSE(0) -  Microcode command failed.
+ *      ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ *                      may be hung which requires driver recovery.
  */
 STATIC int
 AdvResetSB(ADV_DVC_VAR *asc_dvc)
 {
     int         status;
 
-    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0);
+    /*
+     * Send the SCSI Bus Reset idle start idle command which asserts
+     * the SCSI Bus Reset signal.
+     */
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L);
+    if (status != ADV_TRUE)
+    {
+        return status;
+    }
+
+    /*
+     * Delay for the specified SCSI Bus Reset hold time.
+     *
+     * The hold time delay is done on the host because the RISC has no
+     * microsecond accurate timer.
+     */
+    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+
+    /*
+     * Send the SCSI Bus Reset end idle command which de-asserts
+     * the SCSI Bus Reset signal and purges any pending requests.
+     */
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L);
+    if (status != ADV_TRUE)
+    {
+        return status;
+    }
 
-    AdvResetSCSIBus(asc_dvc);
+    DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
 
     return status;
 }
 
 /*
- * Reset SCSI Bus and delay.
+ * Reset chip and SCSI Bus.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
+ *      ADV_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
  */
-STATIC void
-AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc)
+STATIC int
+AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr    iop_base;
-    ushort         scsi_ctrl;
+    int         status;
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    uchar       tid, max_cmd[ADV_MAX_TID + 1];
+    AdvPortAddr iop_base;
+    ushort      bios_sig;
 
     iop_base = asc_dvc->iop_base;
 
     /*
-     * The microcode currently sets the SCSI Bus Reset signal while
-     * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above.
-     * But the SCSI Bus Reset Hold Time in the microcode is not deterministic
-     * (it may in fact be for less than the SCSI Spec. minimum of 25 us).
-     * Therefore on return the Adv Library sets the SCSI Bus Reset signal
-     * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
-     * than 25 us.
-     */
-    scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL);
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
-        scsi_ctrl | ADV_SCSI_CTRL_RSTOUT);
-    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
-        scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT);
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
 
-    DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
-}
+    /*
+     * Force the AdvInitAsc3550/38C0800Driver() function to
+     * perform a SCSI Bus Reset by clearing the BIOS signature word.
+     * The initialization functions assumes a SCSI Bus Reset is not
+     * needed if the BIOS signature word is present.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
 
+    /*
+     * Stop chip and reset it.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+    DvcSleepMilliSecond(100);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+
+    /*
+     * Reset Adv Library error code, if any, and try
+     * re-initializing the chip.
+     */
+    asc_dvc->err_code = 0;
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        status = AdvInitAsc38C0800Driver(asc_dvc);
+    } else
+    {
+        status = AdvInitAsc3550Driver(asc_dvc);
+    }
+
+    /* Translate initialization return value to status value. */
+    if (status == 0)
+    {
+        status = ADV_TRUE;
+    } else
+    {
+        status = ADV_FALSE;
+    }
+
+    /*
+     * Restore the BIOS signature word.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+
+    /*
+     * Restore per TID negotiated values.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    return status;
+}
 
 /*
  * Adv Library Interrupt Service Routine
@@ -14944,79 +17725,76 @@
 {
     AdvPortAddr                 iop_base;
     uchar                       int_stat;
-    ushort                      next_done_loc, target_bit;
-    int                         completed_q;
+    ushort                      target_bit;
+    ADV_CARR_T                  *free_carrp;
+    ulong                       irq_next_vpa;
     int                         flags;
     ADV_SCSI_REQ_Q              *scsiq;
-    ASC_REQ_SENSE               *sense_data;
-    int                         ret;
 
     flags = DvcEnterCritical();
-    iop_base = asc_dvc->iop_base;
 
-    if (AdvIsIntPending(iop_base))
-    {
-        ret = ADV_TRUE;
-    } else
-    {
-        ret = ADV_FALSE;
-    }
+    iop_base = asc_dvc->iop_base;
 
     /* Reading the register clears the interrupt. */
     int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
 
-    if (int_stat & ADV_INTR_STATUS_INTRB)
+    if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+         ADV_INTR_STATUS_INTRC)) == 0)
     {
-        asc_dvc->idle_cmd_done = ADV_TRUE;
+        return ADV_FALSE;
     }
 
     /*
-     * Notify the driver of a hardware detected SCSI Bus Reset.
+     * Notify the driver of an asynchronous microcode condition by
+     * calling the ADV_DVC_VAR.async_callback function. The function
+     * is passed the microcode ASC_MC_INTRB_CODE byte value.
      */
-    if (int_stat & ADV_INTR_STATUS_INTRC)
+    if (int_stat & ADV_INTR_STATUS_INTRB)
     {
-        if (asc_dvc->sbreset_callback != 0)
+        uchar intrb_code;
+
+        AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+        if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+            asc_dvc->carr_pending_cnt != 0)
+        {
+            AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+            if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+            {
+                AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+            }
+        }
+
+        if (asc_dvc->async_callback != 0)
         {
-            (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc);
+            (*asc_dvc->async_callback)(asc_dvc, intrb_code);
         }
     }
 
     /*
-     * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC
-     * Queue List request. Its forward pointer (RQL_FWD) points to the
-     * current completed RISC Queue List request.
+     * Check if the IRQ stopper carrier contains a completed request.
      */
-    AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc);
-    next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
-        (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD;
-
-    AdvReadByteLram(iop_base, next_done_loc, completed_q);
-
-    /* Loop until all completed Q's are processed. */
-    while (completed_q != ASC_MC_NULL_Q)
+    while (((irq_next_vpa = asc_dvc->irq_sp->next_vpa) & ASC_RQ_DONE) != 0)
     {
-        AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q);
-
-        next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
-          (completed_q * ASC_MC_RISC_Q_LIST_SIZE);
+        /*
+         * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+         * The RISC will have set 'areq_vpa' to a virtual address.
+         */
+        scsiq = (ADV_SCSI_REQ_Q *) asc_dvc->irq_sp->areq_vpa;
 
         /*
-         * Read the ADV_SCSI_REQ_Q virtual address pointer from
-         * the RISC list entry. The microcode has changed the
-         * ADV_SCSI_REQ_Q physical address to its virtual address.
-         *
-         * Refer to comments at the end of AdvSendScsiCmd() for
-         * more information on the RISC list structure.
+         * Advance the stopper pointer to the next carrier
+         * ignoring the lower four bits. Free the previous
+         * stopper carrier.
          */
-        {
-            ushort lsw, msw;
-            AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw);
-            AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw);
+        free_carrp = asc_dvc->irq_sp;
+        asc_dvc->irq_sp = ASC_GET_CARRP(irq_next_vpa);
+
+        free_carrp->next_vpa = (ulong) asc_dvc->carr_freelist;
+        asc_dvc->carr_freelist = (ADV_CARR_T *) free_carrp;
+        asc_dvc->carr_pending_cnt--;
 
-            scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw);
-        }
-        ADV_ASSERT(scsiq != NULL);
 
+        ADV_ASSERT(scsiq != NULL);
         target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
 
         /*
@@ -15028,14 +17806,9 @@
          * Check Condition handling
          */
         if ((scsiq->done_status == QD_WITH_ERROR) &&
-            (scsiq->scsi_status == SS_CHK_CONDITION) &&
-            (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 &&
-            (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN)
+            (scsiq->scsi_status == SS_CHK_CONDITION)
+            )
         {
-            /*
-             * Command returned with a check condition and valid
-             * sense data.
-             */
         }
         /*
          * If the command that completed was a SCSI INQUIRY and
@@ -15043,27 +17816,18 @@
          * command information for the device.
          */
         else if (scsiq->done_status == QD_NO_ERROR &&
-                   scsiq->cdb[0] == SCSICMD_Inquiry &&
-                   scsiq->target_lun == 0)
+                 scsiq->cdb[0] == SCSICMD_Inquiry &&
+                 scsiq->target_lun == 0)
         {
             AdvInquiryHandling(asc_dvc, scsiq);
         }
 
-        
-        /* Change the RISC Queue List state to free. */
-        AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE);
-
-        /* Get the RISC Queue List forward pointer. */
-        AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q);
-
         /*
          * Notify the driver of the completed request by passing
          * the ADV_SCSI_REQ_Q pointer to its callback function.
          */
-        ADV_ASSERT(asc_dvc->cur_host_qng > 0);
-        asc_dvc->cur_host_qng--;
         scsiq->a_flag |= ADV_SCSIQ_DONE;
-        (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq);
+        (*asc_dvc->isr_callback)(asc_dvc, scsiq);
         /*
          * Note: After the driver callback function is called, 'scsiq'
          * can no longer be referenced.
@@ -15083,231 +17847,107 @@
         (void) DvcEnterCritical();
     }
     DvcLeaveCritical(flags);
-    return ret;
+    return ADV_TRUE;
 }
 
 /*
  * Send an idle command to the chip and wait for completion.
  *
- * Interrupts do not have to be enabled on entry.
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
  *
  * Return Values:
  *   ADV_TRUE - command completed successfully
  *   ADV_FALSE - command failed
+ *   ADV_ERROR - command timed out
  */
 STATIC int
 AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
                ushort idle_cmd,
-               ulong idle_cmd_parameter,
-               int flags)
+               ulong idle_cmd_parameter)
 {
     int         last_int_level;
-    ulong       i;
+    int         result;
+    ulong       i, j;
     AdvPortAddr iop_base;
-    int         ret;
-
-    asc_dvc->idle_cmd_done = 0;
 
     last_int_level = DvcEnterCritical();
+
     iop_base = asc_dvc->iop_base;
 
     /*
+     * Clear the idle command status which is set by the microcode
+     * to a non-zero value to indicate when the command is completed.
+     * The non-zero result is one of the IDLE_CMD_STATUS_* values
+     * defined in a_advlib.h.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0);
+
+    /*
      * Write the idle command value after the idle command parameter
      * has been written to avoid a race condition. If the order is not
      * followed, the microcode may process the idle command before the
      * parameters have been written to LRAM.
      */
-    AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter);
+    AdvWriteDWordLram(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+        idle_cmd_parameter);
     AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
-    DvcLeaveCritical(last_int_level);
 
     /*
-     * If the 'flags' argument contains the ADV_NOWAIT flag, then
-     * return with success.
+     * Tickle the RISC to tell it to process the idle command.
      */
-    if (flags & ADV_NOWAIT)
+    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
     {
-        return ADV_TRUE;
-    }
-
-    for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++)
-    {
-        /*
-         * 'idle_cmd_done' is set by AdvISR().
-         */
-        if (asc_dvc->idle_cmd_done)
-        {
-            break;
-        }
-        DvcSleepMilliSecond(1);
-
         /*
-         * If interrupts were disabled on entry to AdvSendIdleCmd(),
-         * then they will still be disabled here. Call AdvISR() to
-         * check for the idle command completion.
+         * Clear the tickle value. In the ASC-3550 the RISC flag
+         * command 'clr_tickle_b' does not work unless the host
+         * value is cleared.
          */
-        (void) AdvISR(asc_dvc);
-    }
-
-    last_int_level = DvcEnterCritical();
-
-    if (asc_dvc->idle_cmd_done == ADV_FALSE)
-    {
-        ADV_ASSERT(0); /* The idle command should never timeout. */
-        return ADV_FALSE;
-    } else
-    {
-        AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret);
-        return ret;
-    }
-}
-
-/*
- * Send the SCSI request block to the adapter
- *
- * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the
- * following structure:
- *
- * 0: RQL_FWD - RISC list forward pointer (1 byte)
- * 1: RQL_BWD - RISC list backward pointer (1 byte)
- * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte)
- * 3: RQL_TID - request target id (1 byte)
- * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes)
- *
- * Return:
- *      ADV_SUCCESS(1) - the request is in the mailbox
- *      ADV_BUSY(0) - total request count > 253, try later
- */
-STATIC int
-AdvSendScsiCmd(
-    ADV_DVC_VAR *asc_dvc,
-    ADV_SCSI_REQ_Q  *scsiq)
-{
-    ushort                 next_ready_loc;
-    uchar                  next_ready_loc_fwd;
-    int                    last_int_level;
-    AdvPortAddr            iop_base;
-    long                   req_size;
-    ulong                  q_phy_addr;
-
-    /*
-     * The ADV_SCSI_REQ_Q 'target_id' field should never be equal
-     * to the host adapter ID or exceed ADV_MAX_TID.
-     */
-    if (scsiq->target_id == asc_dvc->chip_scsi_id ||
-        scsiq->target_id > ADV_MAX_TID)
-    {
-        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
-        scsiq->done_status = QD_WITH_ERROR;
-        return ADV_ERROR;
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
     }
 
-    iop_base = asc_dvc->iop_base;
-
-    last_int_level = DvcEnterCritical();
-
-    if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng)
-    {
-        DvcLeaveCritical(last_int_level);
-        return ADV_BUSY;
-    } else
+    /* Wait for up to 100 millisecond for the idle command to timeout. */
+    for (i = 0; i < SCSI_WAIT_100_MSEC; i++)
     {
-        ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT);
-        asc_dvc->cur_host_qng++;
+        /* Poll once each microsecond for command completion. */
+        for (j = 0; j < SCSI_US_PER_MSEC; j++)
+        {
+            AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result);
+            if (result != 0)
+            {
+                DvcLeaveCritical(last_int_level);
+                return result;
+            }
+            DvcDelayMicroSecond(asc_dvc, (ushort) 1);
+        }
     }
 
-    /*
-     * Clear the ADV_SCSI_REQ_Q done flag.
-     */
-    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
-
-    /*
-     * Save the original sense buffer length.
-     *
-     * After the request completes 'sense_len' will be set to the residual
-     * byte count of the Auto-Request Sense if a command returns CHECK
-     * CONDITION and the Sense Data is valid indicated by 'host_status' not
-     * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid
-     * Sense Data Length subtract 'sense_len' from 'orig_sense_len'.
-     */
-    scsiq->orig_sense_len = scsiq->sense_len;
-
-    AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc);
-    next_ready_loc = ASC_MC_RISC_Q_LIST_BASE +
-        (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE);
-
-    /*
-     * Write the physical address of the Q to the mailbox.
-     * We need to skip the first four bytes, because the microcode
-     * uses them internally for linking Q's together.
-     */
-    req_size = sizeof(ADV_SCSI_REQ_Q);
-    q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq,
-                    (uchar *) scsiq, &req_size,
-                    ADV_IS_SCSIQ_FLAG);
-    ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr);
-    ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
-
-    scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
-
-    /*
-     * The RISC list structure, which 'next_ready_loc' is a pointer
-     * to in microcode LRAM, has the format detailed in the comment
-     * header for this function.
-     *
-     * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request.
-     */
-    AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr);
-
-    /* Write target_id to 'next_ready_loc' request. */
-    AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id);
-
-    /*
-     * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to
-     * the 'next_ready_loc' request forward pointer.
-     *
-     * Do this *before* changing the 'next_ready_loc' queue to QS_READY.
-     * After the state is changed to QS_READY 'RQL_FWD' will be changed
-     * by the microcode.
-     *
-     * NOTE: The temporary variable 'next_ready_loc_fwd' is required to
-     * prevent some compilers from optimizing out 'AdvReadByteLram()' if
-     * it were used as the 3rd argument to 'AdvWriteByteLram()'.
-     */
-    AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd);
-    AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd);
-
-    /*
-     * Change the state of 'next_ready_loc' request from QS_FREE to
-     * QS_READY which will cause the microcode to pick it up and
-     * execute it.
-     *
-     * Can't reference 'next_ready_loc' after changing the request
-     * state to QS_READY. The microcode now owns the request.
-     */
-    AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY);
-
+    ADV_ASSERT(0); /* The idle command should never timeout. */
     DvcLeaveCritical(last_int_level);
-    return ADV_SUCCESS;
+    return ADV_ERROR;
 }
 
 /*
  * Inquiry Information Byte 7 Handling
  *
  * Handle SCSI Inquiry Command information for a device by setting
- * microcode operating variables that affect WDTR, SDTR, and Tag 
+ * microcode operating variables that affect WDTR, SDTR, and Tag
  * Queuing.
  */
 STATIC void
 AdvInquiryHandling(
-    ADV_DVC_VAR          *asc_dvc,
-    ADV_SCSI_REQ_Q       *scsiq)
+    ADV_DVC_VAR                 *asc_dvc,
+    ADV_SCSI_REQ_Q              *scsiq)
 {
-    AdvPortAddr          iop_base;
-    uchar                tid;
-    ASC_SCSI_INQUIRY     *inq;
-    ushort               tidmask;
-    ushort               cfg_word;
+    AdvPortAddr                 iop_base;
+    uchar                       tid;
+    ADV_SCSI_INQUIRY            *inq;
+    ushort                      tidmask;
+    ushort                      cfg_word;
 
     /*
      * AdvInquiryHandling() requires up to INQUIRY information Byte 7
@@ -15318,6 +17958,7 @@
      * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
      * microcode to the transfer residual count.
      */
+
     if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8)
     {
         return;
@@ -15325,12 +17966,13 @@
 
     iop_base = asc_dvc->iop_base;
     tid = scsiq->target_id;
-    inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+    inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
 
     /*
      * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
      */
-    if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2)
+    if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2)
     {
         return;
     } else
@@ -15354,7 +17996,7 @@
          * device's 'wdtr_able' bit and write the new value to the
          * microcode.
          */
-        if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16)
+        if ((asc_dvc->wdtr_able & tidmask) && inq->WBus16)
         {
             AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
             if ((cfg_word & tidmask) == 0)
@@ -15363,10 +18005,15 @@
                 AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
 
                 /*
-                 * Clear the microcode "WDTR negotiation" done indicator
-                 * for the target to cause it to negotiate with the new
-                 * setting set above.
+                 * Clear the microcode "SDTR negotiation" and "WDTR
+                 * negotiation" done indicators for the target to cause
+                 * it to negotiate with the new setting set above.
+                 * WDTR when accepted causes the target to enter
+                 * asynchronous mode, so SDTR must be negotiated.
                  */
+                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
                 AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
                 cfg_word &= ~tidmask;
                 AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
@@ -15380,7 +18027,7 @@
          * supports synchronous transfers, then turn on the device's
          * 'sdtr_able' bit. Write the new value to the microcode.
          */
-        if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync)
+        if ((asc_dvc->sdtr_able & tidmask) && inq->Sync)
         {
             AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
             if ((cfg_word & tidmask) == 0)
@@ -15400,8 +18047,8 @@
         }
 
         /*
-         * If the EEPROM enabled Tag Queuing for device and the
-         * device supports Tag Queuing, then turn on the device's
+         * If the EEPROM enabled Tag Queuing for the device and the
+         * device supports Tag Queueing, then turn on the device's
          * 'tagqng_enable' bit in the microcode and set the microcode
          * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
          * value.
@@ -15411,11 +18058,12 @@
          * disabling Tag Queuing in the BIOS devices with Tag Queuing
          * bugs will at least work with the BIOS.
          */
-        if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue)
+        if ((asc_dvc->tagqng_able & tidmask) && inq->CmdQue)
         {
             AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
             cfg_word |= tidmask;
             AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+
             AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
                 asc_dvc->max_dvc_qng);
         }
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.3.16/linux/drivers/scsi/hosts.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/hosts.c	Tue Sep  7 10:20:11 1999
@@ -758,11 +758,11 @@
  * Why is this a separate function?  Because the kernel_thread code
  * effectively does a fork, and there is a builtin exit() call when
  * the child returns.   The difficulty is that scsi_init() is
- * marked __initfunc(), which means the memory is unmapped after bootup
+ * marked __init, which means the memory is unmapped after bootup
  * is complete, which means that the thread's exit() call gets wiped.
  *
  * The lesson is to *NEVER*, *NEVER* call kernel_thread() from an
- * __initfunc() function, if that function could ever return.
+ * __init function, if that function could ever return.
  */
 static void launch_error_handler_thread(struct Scsi_Host * shpnt)
 {
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/i60uscsi.c linux/drivers/scsi/i60uscsi.c
--- v2.3.16/linux/drivers/scsi/i60uscsi.c	Mon Jul  5 20:36:12 1999
+++ linux/drivers/scsi/i60uscsi.c	Thu Sep  2 10:03:26 1999
@@ -64,16 +64,21 @@
  * 09/24/98 hl - v1.01b Fixed reset.
  * 10/05/98 hl - v1.02 split the source code and release.
  * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
+ * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
+ * 08/08/99 bv - v1.02c Use waitForPause again.
  **************************************************************************/
 
 #ifndef CVT_LINUX_VERSION
 #define CVT_LINUX_VERSION(V,P,S)        (V * 65536 + P * 256 + S)
 #endif
 
+#include <linux/version.h>
 #include <linux/sched.h>
 #include <asm/io.h>
 #include "i60uscsi.h"
 
+#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
+#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
 
 /* ---- INTERNAL FUNCTIONS ---- */
 static UCHAR waitChipReady(ORC_HCS * hcsp);
@@ -155,7 +160,7 @@
 /***************************************************************************/
 static void waitForPause(unsigned amount)
 {
-	ULONG the_time = jiffies + amount;	/* 0.01 seconds per jiffy */
+	ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 	while (time_before_eq(jiffies, the_time));
@@ -169,10 +174,10 @@
 {
 	int i;
 
-	for (i = 0; i < 2000; i++) {	/* Wait 1 second for report timeout     */
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
 		if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP)	/* Wait HOSTSTOP set */
 			return (TRUE);
-		waitForPause(5);	/* wait 500ms before try again  */
+		waitForPause(100);	/* wait 100ms before try again  */
 	}
 	return (FALSE);
 }
@@ -182,10 +187,10 @@
 {
 	int i;
 
-	for (i = 0; i < 2000; i++) {	/* Wait 1 second for report timeout     */
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
 		if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY)		/* Wait READY set */
 			return (TRUE);
-		waitForPause(5);	/* wait 500ms before try again  */
+		waitForPause(100);	/* wait 100ms before try again  */
 	}
 	return (FALSE);
 }
@@ -195,10 +200,10 @@
 {
 	int i;
 
-	for (i = 0; i < 2000; i++) {	/* Wait 1 second for report timeout     */
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
 		if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST))	/* Wait SCSIRST done */
 			return (TRUE);
-		waitForPause(5);	/* wait 500ms before try again  */
+		waitForPause(100);	/* wait 100ms before try again  */
 	}
 	return (FALSE);
 }
@@ -208,10 +213,10 @@
 {
 	int i;
 
-	for (i = 0; i < 2000; i++) {	/* Wait 1 second for report timeout     */
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
 		if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO))		/* Wait HDO off */
 			return (TRUE);
-		waitForPause(5);	/* wait 500ms before try again  */
+		waitForPause(100);	/* wait 100ms before try again  */
 	}
 	return (FALSE);
 }
@@ -221,10 +226,10 @@
 {
 	int i;
 
-	for (i = 0; i < 2000; i++) {	/* Wait 1 second for report timeout     */
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
 		if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
 			return (TRUE);	/* Wait HDI set */
-		waitForPause(5);	/* wait 500ms before try again  */
+		waitForPause(100);	/* wait 100ms before try again  */
 	}
 	return (FALSE);
 }
@@ -463,15 +468,9 @@
 	pVirEscb = (ESCB *) hcsp->HCS_virEscbArray;
 
 	for (i = 0; i < orc_num_scb; i++) {
-#if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
-		pPhysEscb = (PVOID) ((ULONG) hcsp->HCS_virEscbArray + (sizeof(ESCB) * i));
-		pVirScb->SCB_SGPAddr = (U32) VIRT_TO_BUS(pPhysEscb);
-		pVirScb->SCB_SensePAddr = (U32) VIRT_TO_BUS(pPhysEscb);
-#else
 		pPhysEscb = (PVOID) (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
 		pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
 		pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
-#endif
 		pVirScb->SCB_EScb = pVirEscb;
 		pVirScb->SCB_ScbIdx = i;
 		pVirScb++;
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/i60uscsi.h linux/drivers/scsi/i60uscsi.h
--- v2.3.16/linux/drivers/scsi/i60uscsi.h	Wed Feb 24 16:27:54 1999
+++ linux/drivers/scsi/i60uscsi.h	Thu Sep  2 10:03:26 1999
@@ -60,8 +60,6 @@
  *	12/19/98 bv, v1.02a Use spinlocks for 2.1.95 and up.
  **************************************************************************/
 
-#include <linux/config.h>
-
 #define ULONG   unsigned long
 #define PVOID   void *
 #define USHORT  unsigned short
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c
--- v2.3.16/linux/drivers/scsi/in2000.c	Thu Aug 27 16:41:29 1998
+++ linux/drivers/scsi/in2000.c	Thu Sep  2 10:03:26 1999
@@ -1845,7 +1845,7 @@
 static char setup_used[MAX_SETUP_ARGS];
 static int done_setup = 0;
 
-in2000__INITFUNC( void in2000_setup (char *str, int *ints) )
+void __init in2000_setup (char *str, int *ints)
 {
 int i;
 char *p1,*p2;
@@ -1877,7 +1877,7 @@
 /* check_setup_args() returns index if key found, 0 if not
  */
 
-in2000__INITFUNC( static int check_setup_args(char *key, int *flags, int *val, char *buf) )
+static int __init check_setup_args(char *key, int *flags, int *val, char *buf)
 {
 int x;
 char *cp;
@@ -1931,7 +1931,7 @@
    };
 
 
-in2000__INITFUNC( int in2000_detect(Scsi_Host_Template * tpnt) )
+int __init in2000_detect(Scsi_Host_Template * tpnt)
 {
 struct Scsi_Host *instance;
 struct IN2000_hostdata *hostdata;
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/inia100.c linux/drivers/scsi/inia100.c
--- v2.3.16/linux/drivers/scsi/inia100.c	Mon Aug  9 10:25:01 1999
+++ linux/drivers/scsi/inia100.c	Thu Sep  2 10:03:26 1999
@@ -73,13 +73,19 @@
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 #include <stdarg.h>
+#include <asm/io.h>
 #include <asm/irq.h>
+#include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
 #include <linux/delay.h>
+#include <linux/sched.h>
 #if LINUX_VERSION_CODE <= CVT_LINUX_VERSION(2,1,92)
 #include <linux/bios32.h>
 #endif
 #include <linux/pci.h>
+#include <linux/proc_fs.h>
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,23)
 #include <linux/init.h>
 #endif
@@ -87,27 +93,34 @@
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(2,1,95)
 #include <asm/spinlock.h>
 #endif
+#include "sd.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "inia100.h"
 #include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
 
 #else
 
+#include <linux/kernel.h>
 #include <linux/head.h>
 #include <linux/types.h>
-#include <asm/system.h>
-#include "../block/blk.h"
-#endif
-
-#include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
+
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
+#include <asm/system.h>
 #include <asm/io.h>
+#include "../block/blk.h"
 #include "scsi.h"
 #include "sd.h"
 #include "hosts.h"
 #include <linux/malloc.h>
 #include "inia100.h"
+#endif
 
 #ifdef MODULE
 Scsi_Host_Template driver_template = INIA100;
@@ -119,7 +132,7 @@
 char *inia100_Copyright = "Copyright (C) 1998-99";
 char *inia100_InitioName = "by Initio Corporation";
 char *inia100_ProductName = "INI-A100U2W";
-char *inia100_Version = "v1.02a";
+char *inia100_Version = "v1.02c";
 
 #if LINUX_VERSION_CODE >= CVT_LINUX_VERSION(1,3,0)
 struct proc_dir_entry proc_scsi_inia100 =
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/inia100.h linux/drivers/scsi/inia100.h
--- v2.3.16/linux/drivers/scsi/inia100.h	Wed Aug 18 16:44:58 1999
+++ linux/drivers/scsi/inia100.h	Tue Sep  7 11:50:58 1999
@@ -83,7 +83,7 @@
 extern int inia100_biosparam(Disk *, int, int *);	/*for linux v1.13 */
 #endif
 
-#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02a"
+#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02c"
 
 #if LINUX_VERSION_CODE < CVT_LINUX_VERSION(1, 3, 0)
 #define INIA100	{ \
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/mca_53c9x.c linux/drivers/scsi/mca_53c9x.c
--- v2.3.16/linux/drivers/scsi/mca_53c9x.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/mca_53c9x.c	Tue Sep  7 10:14:37 1999
@@ -157,7 +157,7 @@
 			{
 				printk("Unable to request IRQ %d.\n", esp->irq);
 				esp_deallocate(esp);
-				unregister_scsi(esp->ehost);
+				scsi_unregister(esp->ehost);
 				return 0;
 			}
 
@@ -166,7 +166,7 @@
 				 esp->dma);
 				free_irq(esp->irq, esp_intr);
 				esp_deallocate(esp);
-				unregister_scsi(esp->ehost);
+				scsi_unregister(esp->ehost);
 				return 0;
 			}
 
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.3.16/linux/drivers/scsi/scsi.c	Mon Aug  9 19:21:33 1999
+++ linux/drivers/scsi/scsi.c	Sat Sep  4 10:48:46 1999
@@ -71,8 +71,8 @@
 #undef USE_STATIC_SCSI_MEMORY
 
 /*
-static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
-*/
+   static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
+ */
 
 /*
  * Definitions and constants.
@@ -87,11 +87,11 @@
 #define SECTORS_PER_PAGE	(PAGE_SIZE/SECTOR_SIZE)
 
 #if SECTORS_PER_PAGE <= 8
- typedef unsigned char	FreeSectorBitmap;
+typedef unsigned char FreeSectorBitmap;
 #elif SECTORS_PER_PAGE <= 32
- typedef unsigned int	FreeSectorBitmap;
+typedef unsigned int FreeSectorBitmap;
 #else
-# error You lose.
+#error You lose.
 #endif
 
 #define MIN_RESET_DELAY (2*HZ)
@@ -116,60 +116,63 @@
 /*
  * Data declarations.
  */
-unsigned long             scsi_pid = 0;
-Scsi_Cmnd               * last_cmnd = NULL;
+unsigned long scsi_pid = 0;
+Scsi_Cmnd *last_cmnd = NULL;
 /* Command groups 3 and 4 are reserved and should never be used.  */
-const unsigned char       scsi_command_size[8] = { 6, 10, 10, 12, 
-                                                   12, 12, 10, 10 };
-static unsigned long      serial_number = 0;
-static Scsi_Cmnd        * scsi_bh_queue_head = NULL;
-static Scsi_Cmnd	* scsi_bh_queue_tail = NULL;
-static FreeSectorBitmap * dma_malloc_freelist = NULL;
-static int                need_isa_bounce_buffers;
-static unsigned int       dma_sectors = 0;
-unsigned int              scsi_dma_free_sectors = 0;
-unsigned int              scsi_need_isa_buffer = 0;
-static unsigned char   ** dma_malloc_pages = NULL;
+const unsigned char scsi_command_size[8] = {
+	6, 10, 10, 12,
+	12, 12, 10, 10
+};
+static unsigned long serial_number = 0;
+static Scsi_Cmnd *scsi_bh_queue_head = NULL;
+static Scsi_Cmnd *scsi_bh_queue_tail = NULL;
+static FreeSectorBitmap *dma_malloc_freelist = NULL;
+static int need_isa_bounce_buffers;
+static unsigned int dma_sectors = 0;
+unsigned int scsi_dma_free_sectors = 0;
+unsigned int scsi_need_isa_buffer = 0;
+static unsigned char **dma_malloc_pages = NULL;
 
 /*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
-unsigned int              scsi_logging_level = 0;
+unsigned int scsi_logging_level = 0;
 
-volatile struct Scsi_Host * host_active = NULL;
+volatile struct Scsi_Host *host_active = NULL;
 
 #if CONFIG_PROC_FS
 /* 
  * This is the pointer to the /proc/scsi code.
  * It is only initialized to !=0 if the scsi code is present
  */
-struct proc_dir_entry proc_scsi_scsi = {
-    PROC_SCSI_SCSI, 4, "scsi",
-    S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
-    NULL,
-    NULL, NULL,
-    NULL, NULL, NULL
+struct proc_dir_entry proc_scsi_scsi =
+{
+	PROC_SCSI_SCSI, 4, "scsi",
+	S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
+	NULL,
+	NULL, NULL,
+	NULL, NULL, NULL
 };
 #endif
 
 
 const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
 {
-    "Direct-Access    ",
-    "Sequential-Access",
-    "Printer          ",
-    "Processor        ",
-    "WORM             ",
-    "CD-ROM           ",
-    "Scanner          ",
-    "Optical Device   ",
-    "Medium Changer   ",
-    "Communications   ",
-    "Unknown          ",
-    "Unknown          ",
-    "Unknown          ",
-    "Enclosure        ",
+	"Direct-Access    ",
+	"Sequential-Access",
+	"Printer          ",
+	"Processor        ",
+	"WORM             ",
+	"CD-ROM           ",
+	"Scanner          ",
+	"Optical Device   ",
+	"Medium Changer   ",
+	"Communications   ",
+	"Unknown          ",
+	"Unknown          ",
+	"Unknown          ",
+	"Enclosure        ",
 };
 
 /* 
@@ -177,23 +180,23 @@
  */
 static void resize_dma_pool(void);
 static void print_inquiry(unsigned char *data);
-extern void scsi_times_out (Scsi_Cmnd * SCpnt);
-static int  scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
-                 int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
-                 struct Scsi_Host *shpnt, char * scsi_result);
-void        scsi_build_commandblocks(Scsi_Device * SDpnt);
-static int scsi_unregister_device(struct Scsi_Device_Template * tpnt);
+extern void scsi_times_out(Scsi_Cmnd * SCpnt);
+static int scan_scsis_single(int channel, int dev, int lun, int *max_scsi_dev,
+		int *sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
+			     struct Scsi_Host *shpnt, char *scsi_result);
+void scsi_build_commandblocks(Scsi_Device * SDpnt);
+static int scsi_unregister_device(struct Scsi_Device_Template *tpnt);
 
 /*
  * These are the interface to the old error handling code.  It should go away
  * someday soon.
  */
-extern void scsi_old_done (Scsi_Cmnd *SCpnt);
-extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+extern void scsi_old_done(Scsi_Cmnd * SCpnt);
+extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);
 
 #if CONFIG_PROC_FS
-extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
-				      off_t offset, int length, int inout);
+extern int (*dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
+				    off_t offset, int length, int inout);
 extern int dispatch_scsi_info(int ino, char *buffer, char **start,
 			      off_t offset, int length, int inout);
 #endif
@@ -207,11 +210,11 @@
 static void scsi_dump_status(int level);
 
 
-struct dev_info{
-    const char * vendor;
-    const char * model;
-    const char * revision; /* Latest revision known to be bad.  Not used yet */
-    unsigned flags;
+struct dev_info {
+	const char *vendor;
+	const char *model;
+	const char *revision;	/* Latest revision known to be bad.  Not used yet */
+	unsigned flags;
 };
 
 /*
@@ -221,99 +224,106 @@
  */
 static struct dev_info device_list[] =
 {
-{"Aashima","IMAGERY 2400SP","1.03",BLIST_NOLUN},/* Locks up if polled for lun != 0 */
-{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
-{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
-{"DENON","DRD-25X","V", BLIST_NOLUN},           /* Locks up if probed for lun != 0 */
-{"HITACHI","DK312C","CM81", BLIST_NOLUN},       /* Responds to all lun - dtg */
-{"HITACHI","DK314C","CR21" , BLIST_NOLUN},      /* responds to all lun */
-{"IMS", "CDD521/10","2.06", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","XT-3280","PR02", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","XT-4380S","B3C", BLIST_NOLUN},       /* Locks-up when LUN>0 polled. */
-{"MAXTOR","MXT-1240S","I1.2", BLIST_NOLUN},     /* Locks up when LUN>0 polled */
-{"MAXTOR","XT-4170S","B5A", BLIST_NOLUN},       /* Locks-up sometimes when LUN>0 polled. */
-{"MAXTOR","XT-8760S","B7B", BLIST_NOLUN},       /* guess what? */
-{"MEDIAVIS","RENO CD-ROMX2A","2.03",BLIST_NOLUN},/*Responds to all lun */
-{"MICROP", "4110", "*", BLIST_NOTQ},		/* Buggy Tagged Queuing */
-{"NEC","CD-ROM DRIVE:841","1.0", BLIST_NOLUN},  /* Locks-up when LUN>0 polled. */
-{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},    /* Responds to all lun */
-{"RODIME","RO3000S","2.33", BLIST_NOLUN},       /* Locks up if polled for lun != 0 */
-{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},     /* causes failed REQUEST SENSE on lun 1
-						 * for aha152x controller, which causes
-						 * SCSI code to reset bus.*/
-{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},   /* causes failed REQUEST SENSE on lun 1
-						 * for aha152x controller, which causes
-						 * SCSI code to reset bus.*/
-{"SEAGATE", "ST296","921", BLIST_NOLUN},        /* Responds to all lun */
-{"SEAGATE","ST1581","6538",BLIST_NOLUN},	/* Responds to all lun */
-{"SONY","CD-ROM CDU-541","4.3d", BLIST_NOLUN},
-{"SONY","CD-ROM CDU-55S","1.0i", BLIST_NOLUN},
-{"SONY","CD-ROM CDU-561","1.7x", BLIST_NOLUN},
-{"SONY","CD-ROM CDU-8012","*", BLIST_NOLUN},
-{"TANDBERG","TDC 3600","U07", BLIST_NOLUN},     /* Locks up if polled for lun != 0 */
-{"TEAC","CD-R55S","1.0H", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
-{"TEAC","CD-ROM","1.06", BLIST_NOLUN},          /* causes failed REQUEST SENSE on lun 1
-						 * for seagate controller, which causes
-						 * SCSI code to reset bus.*/
-{"TEXEL","CD-ROM","1.06", BLIST_NOLUN},         /* causes failed REQUEST SENSE on lun 1
-						 * for seagate controller, which causes
-						 * SCSI code to reset bus.*/
-{"QUANTUM","LPS525S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
-{"QUANTUM","PD1225S","3110", BLIST_NOLUN},      /* Locks sometimes if polled for lun != 0 */
-{"MEDIAVIS","CDR-H93MV","1.31", BLIST_NOLUN},   /* Locks up if polled for lun != 0 */
-{"SANKYO", "CP525","6.64", BLIST_NOLUN},        /* causes failed REQ SENSE, extra reset */
-{"HP", "C1750A", "3226", BLIST_NOLUN},          /* scanjet iic */
-{"HP", "C1790A", "", BLIST_NOLUN},              /* scanjet iip */
-{"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
-{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* extra reset */
-{"RELISYS", "Scorpio", "*", BLIST_NOLUN},	/* responds to all LUN */
+	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* Locks up if probed for lun != 0 */
+	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},		/* Responds to all lun - dtg */
+	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},		/* responds to all lun */
+	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
+	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
+	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},		/* Locks-up when LUN>0 polled. */
+	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},		/* Locks up when LUN>0 polled */
+	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},		/* Locks-up sometimes when LUN>0 polled. */
+	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},		/* guess what? */
+	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/*Responds to all lun */
+	{"MICROP", "4110", "*", BLIST_NOTQ},			/* Buggy Tagged Queuing */
+	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},	/* Locks-up when LUN>0 polled. */
+	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},		/* Responds to all lun */
+	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
+	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
+								 * for aha152x controller, which causes
+								 * SCSI code to reset bus.*/
+	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
+								 * for aha152x controller, which causes
+								 * SCSI code to reset bus.*/
+	{"SEAGATE", "ST296", "921", BLIST_NOLUN},		/* Responds to all lun */
+	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},		/* Responds to all lun */
+	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},	
+	{"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-8012", "*", BLIST_NOLUN},
+	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
+	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
+	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
+								 * for seagate controller, which causes
+								 * SCSI code to reset bus.*/
+	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},		/* causes failed REQUEST SENSE on lun 1
+								 * for seagate controller, which causes
+								 * SCSI code to reset bus.*/
+	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},		/* Locks sometimes if polled for lun != 0 */
+	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},		/* Locks sometimes if polled for lun != 0 */
+	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},		/* Locks up if polled for lun != 0 */
+	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},		/* causes failed REQ SENSE, extra reset */
+	{"HP", "C1750A", "3226", BLIST_NOLUN},			/* scanjet iic */
+	{"HP", "C1790A", "", BLIST_NOLUN},			/* scanjet iip */
+	{"HP", "C2500A", "", BLIST_NOLUN},			/* scanjet iicx */
+	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},		/* extra reset */
+	{"RELISYS", "Scorpio", "*", BLIST_NOLUN},		/* responds to all LUN */
 
 /*
  * Other types of devices that have special flags.
  */
-{"SONY","CD-ROM CDU-8001","*", BLIST_BORKEN},
-{"TEXEL","CD-ROM","1.06", BLIST_BORKEN},
-{"IOMEGA","Io20S         *F","*", BLIST_KEY},
-{"INSITE","Floptical   F*8I","*", BLIST_KEY},
-{"INSITE","I325VM","*", BLIST_KEY},
-{"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"REGAL","CDC-4X","*", BLIST_MAX5LUN | BLIST_SINGLELUN},
-{"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"NAKAMICH","MJ-5.16S","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"EMULEX","MD21/S2     ESDI","*", BLIST_SINGLELUN},
-{"CANON","IPUBJD","*", BLIST_SPARSELUN},
-{"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
-{"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
-{"YAMAHA","CDR100","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-{"YAMAHA","CDR102","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
-{"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
-/*
- * Must be at end of list...
- */
-{NULL, NULL, NULL}
+	{"SONY", "CD-ROM CDU-8001", "*", BLIST_BORKEN},
+	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+	{"IOMEGA", "Io20S         *F", "*", BLIST_KEY},
+	{"INSITE", "Floptical   F*8I", "*", BLIST_KEY},
+	{"INSITE", "I325VM", "*", BLIST_KEY},
+	{"NRC", "MBR-7", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7.4", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"REGAL", "CDC-4X", "*", BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-4.8S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-5.16S", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"EMULEX", "MD21/S2     ESDI", "*", BLIST_SINGLELUN},
+	{"CANON", "IPUBJD", "*", BLIST_SPARSELUN},
+	{"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN},
+	{"NEC", "PD-1 ODX654P", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"MATSHITA", "PD", "*", BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+
+	/*
+	 * Must be at end of list...
+	 */
+	{NULL, NULL, NULL}
 };
 
-static int get_device_flags(unsigned char * response_data){
-    int i = 0;
-    unsigned char * pnt;
-    for(i=0; 1; i++){
-	if(device_list[i].vendor == NULL) return 0;
-	pnt = &response_data[8];
-	while(*pnt && *pnt == ' ') pnt++;
-	if(memcmp(device_list[i].vendor, pnt,
-		  strlen(device_list[i].vendor))) continue;
-	pnt = &response_data[16];
-	while(*pnt && *pnt == ' ') pnt++;
-	if(memcmp(device_list[i].model, pnt,
-		  strlen(device_list[i].model))) continue;
-	return device_list[i].flags;
-    }
-    return 0;
+static int get_device_flags(unsigned char *response_data)
+{
+	int i = 0;
+	unsigned char *pnt;
+	for (i = 0; 1; i++) {
+		if (device_list[i].vendor == NULL)
+			return 0;
+		pnt = &response_data[8];
+		while (*pnt && *pnt == ' ')
+			pnt++;
+		if (memcmp(device_list[i].vendor, pnt,
+			   strlen(device_list[i].vendor)))
+			continue;
+		pnt = &response_data[16];
+		while (*pnt && *pnt == ' ')
+			pnt++;
+		if (memcmp(device_list[i].model, pnt,
+			   strlen(device_list[i].model)))
+			continue;
+		return device_list[i].flags;
+	}
+	return 0;
 }
 
 /*
@@ -338,72 +348,74 @@
  *              I (ERY) would like to make this go away someday, but this would
  *              require that we have a recursive mutex object.
  */
-void 
-scsi_make_blocked_list(void)  
+
+void scsi_make_blocked_list(void)
 {
-    int block_count = 0, index;
-    struct Scsi_Host * sh[128], * shpnt;
+	int block_count = 0, index;
+	struct Scsi_Host *sh[128], *shpnt;
 
-    /*
-     * Create a circular linked list from the scsi hosts which have
-     * the "wish_block" field in the Scsi_Host structure set.
-     * The blocked list should include all the scsi hosts using ISA DMA.
-     * In some systems, using two dma channels simultaneously causes
-     * unpredictable results.
-     * Among the scsi hosts in the blocked list, only one host at a time
-     * is allowed to have active commands queued. The transition from
-     * one active host to the next one is allowed only when host_busy == 0
-     * for the active host (which implies host_busy == 0 for all the hosts
-     * in the list). Moreover for block devices the transition to a new
-     * active host is allowed only when a request is completed, since a
-     * block device request can be divided into multiple scsi commands
-     * (when there are few sg lists or clustering is disabled).
-     *
-     * (DB, 4 Feb 1995)
-     */
+	/*
+	 * Create a circular linked list from the scsi hosts which have
+	 * the "wish_block" field in the Scsi_Host structure set.
+	 * The blocked list should include all the scsi hosts using ISA DMA.
+	 * In some systems, using two dma channels simultaneously causes
+	 * unpredictable results.
+	 * Among the scsi hosts in the blocked list, only one host at a time
+	 * is allowed to have active commands queued. The transition from
+	 * one active host to the next one is allowed only when host_busy == 0
+	 * for the active host (which implies host_busy == 0 for all the hosts
+	 * in the list). Moreover for block devices the transition to a new
+	 * active host is allowed only when a request is completed, since a
+	 * block device request can be divided into multiple scsi commands
+	 * (when there are few sg lists or clustering is disabled).
+	 *
+	 * (DB, 4 Feb 1995)
+	 */
 
-   
-    host_active = NULL;
 
-    for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
+	host_active = NULL;
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
 
 #if 0
-	/*
-	 * Is this is a candidate for the blocked list?
-	 * Useful to put into the blocked list all the hosts whose driver
-	 * does not know about the host->block feature.
-	 */
-	if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
+		/*
+		 * Is this is a candidate for the blocked list?
+		 * Useful to put into the blocked list all the hosts whose driver
+		 * does not know about the host->block feature.
+		 */
+		if (shpnt->unchecked_isa_dma)
+			shpnt->wish_block = 1;
 #endif
 
-	if (shpnt->wish_block) sh[block_count++] = shpnt;
-    }
+		if (shpnt->wish_block)
+			sh[block_count++] = shpnt;
+	}
 
-    if (block_count == 1) sh[0]->block = NULL;
+	if (block_count == 1)
+		sh[0]->block = NULL;
 
-    else if (block_count > 1) {
-	
-	for(index = 0; index < block_count - 1; index++) {
-	    sh[index]->block = sh[index + 1];
-	    printk("scsi%d : added to blocked host list.\n",
-		   sh[index]->host_no);
-	}
+	else if (block_count > 1) {
 
-	sh[block_count - 1]->block = sh[0];
-	printk("scsi%d : added to blocked host list.\n",
-	       sh[index]->host_no);
-    }
+		for (index = 0; index < block_count - 1; index++) {
+			sh[index]->block = sh[index + 1];
+			printk("scsi%d : added to blocked host list.\n",
+			       sh[index]->host_no);
+		}
 
+		sh[block_count - 1]->block = sh[0];
+		printk("scsi%d : added to blocked host list.\n",
+		       sh[index]->host_no);
+	}
 }
 
-static void scan_scsis_done (Scsi_Cmnd * SCpnt)
+static void scan_scsis_done(Scsi_Cmnd * SCpnt)
 {
 
-    SCSI_LOG_MLCOMPLETE(1,printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result));
-    SCpnt->request.rq_status = RQ_SCSI_DONE;
+	SCSI_LOG_MLCOMPLETE(1, printk("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result));
+	SCpnt->request.rq_status = RQ_SCSI_DONE;
 
-    if (SCpnt->request.sem != NULL)
-	up(SCpnt->request.sem);
+	if (SCpnt->request.sem != NULL)
+		up(SCpnt->request.sem);
 }
 
 MODULE_PARM(scsi_logging_level, "i");
@@ -411,18 +423,18 @@
 
 #ifndef MODULE
 
-static int __init scsi_logging_setup (char *str)
+static int __init scsi_logging_setup(char *str)
 {
 	int tmp;
 
-	if (get_option(&str, &tmp)==1) {
-	   	scsi_logging_level = (tmp ? ~0 : 0);
+	if (get_option(&str, &tmp) == 1) {
+		scsi_logging_level = (tmp ? ~0 : 0);
 		return 1;
 	} else {
 		printk("scsi_logging_setup : usage scsi_logging_level=n "
-               "(n should be 0 or non-zero)\n");
+		       "(n should be 0 or non-zero)\n");
 		return 0;
-    }
+	}
 }
 
 __setup("scsi_logging=", scsi_logging_setup);
@@ -440,18 +452,18 @@
 
 #ifndef MODULE
 
-static int __init scsi_luns_setup (char *str)
+static int __init scsi_luns_setup(char *str)
 {
 	int tmp;
 
-	if (get_option(&str, &tmp)==1) {
+	if (get_option(&str, &tmp) == 1) {
 		max_scsi_luns = tmp;
 		return 1;
 	} else {
 		printk("scsi_luns_setup : usage max_scsi_luns=n "
-			   "(n should be between 1 and 8)\n");
+		       "(n should be between 1 and 8)\n");
 		return 0;
-    }
+	}
 }
 
 __setup("max_scsi_luns=", scsi_luns_setup);
@@ -465,204 +477,196 @@
  *  lun address of all sequential devices to the tape driver, all random
  *  devices to the disk driver.
  */
-static void scan_scsis (struct Scsi_Host *shpnt, 
-                        unchar hardcoded,
-                        unchar hchannel, 
-                        unchar hid, 
-                        unchar hlun)
-{
-  int             channel;
-  int             dev;
-  int             lun;
-  int             max_dev_lun;
-  Scsi_Cmnd     * SCpnt;
-  unsigned char * scsi_result;
-  unsigned char   scsi_result0[256];
-  Scsi_Device   * SDpnt;
-  Scsi_Device   * SDtail;
-  int             sparse_lun;
-
-  scsi_result = NULL;
-  SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), 
-					  GFP_ATOMIC | GFP_DMA);
-    if (SCpnt) {
-	SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), 
-						 GFP_ATOMIC);
-	if (SDpnt) {
-	    /* Make sure we have something that is valid for DMA purposes */
-	    scsi_result = ( ( !shpnt->unchecked_isa_dma )
-			? &scsi_result0[0] : scsi_init_malloc (512, GFP_DMA));
-	}
-    }
-
-  if (scsi_result == NULL) 
-  {
-      printk ("Unable to obtain scsi_result buffer\n");
-      goto leave;
-  }
-
-  /*
-   * We must chain ourself in the host_queue, so commands can time out 
-   */
-  SCpnt->next = NULL;
-  SDpnt->device_queue = SCpnt;
-  SDpnt->host = shpnt;
-  SDpnt->online = TRUE;
-
-  init_waitqueue_head(&SDpnt->device_wait);
-
-  /*
-   * Next, hook the device to the host in question.
-   */
-  SDpnt->prev = NULL;
-  SDpnt->next = NULL;
-  if( shpnt->host_queue != NULL )
-  {
-      SDtail = shpnt->host_queue;
-      while( SDtail->next != NULL )
-          SDtail = SDtail->next;
-
-      SDtail->next = SDpnt;
-      SDpnt->prev = SDtail;
-  }
-  else
-  {
-      shpnt->host_queue = SDpnt;
-  }
-
-  /*
-   * We need to increment the counter for this one device so we can track when
-   * things are quiet.
-   */
-  atomic_inc(&shpnt->host_active); 
-
-  if (hardcoded == 1) {
-    Scsi_Device *oldSDpnt=SDpnt;
-    struct Scsi_Device_Template * sdtpnt;
-    channel = hchannel;
-    if(channel > shpnt->max_channel) goto leave;
-    dev = hid;
-    if(dev >= shpnt->max_id) goto leave;
-    lun = hlun;
-    if(lun >= shpnt->max_lun) goto leave;
-    scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun,
-		       &SDpnt, SCpnt, shpnt, scsi_result);
-    if(SDpnt!=oldSDpnt) {
-
-	/* it could happen the blockdevice hasn't yet been inited */
-	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-
-	oldSDpnt->scsi_request_fn = NULL;
-	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
-	    if(sdtpnt->attach) {
-		(*sdtpnt->attach)(oldSDpnt);
-		if(oldSDpnt->attached) {
-		    scsi_build_commandblocks(oldSDpnt);
-		    if (0 == oldSDpnt->has_cmdblocks) {
-			printk("scan_scsis: DANGER, no command blocks\n");
-			/* What to do now ?? */
-		    }
+static void scan_scsis(struct Scsi_Host *shpnt,
+		       unchar hardcoded,
+		       unchar hchannel,
+		       unchar hid,
+		       unchar hlun)
+{
+	int channel;
+	int dev;
+	int lun;
+	int max_dev_lun;
+	Scsi_Cmnd *SCpnt;
+	unsigned char *scsi_result;
+	unsigned char scsi_result0[256];
+	Scsi_Device *SDpnt;
+	Scsi_Device *SDtail;
+	int sparse_lun;
+
+	scsi_result = NULL;
+	SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd),
+					       GFP_ATOMIC | GFP_DMA);
+	if (SCpnt) {
+		SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device),
+							 GFP_ATOMIC);
+		if (SDpnt) {
+			/* Make sure we have something that is valid for DMA purposes */
+			scsi_result = ((!shpnt->unchecked_isa_dma)
+				       ? &scsi_result0[0] : scsi_init_malloc(512, GFP_DMA));
+		}
+	}
+	if (scsi_result == NULL) {
+		printk("Unable to obtain scsi_result buffer\n");
+		goto leave;
+	}
+	/*
+	 * We must chain ourself in the host_queue, so commands can time out 
+	 */
+	SCpnt->next = NULL;
+	SDpnt->device_queue = SCpnt;
+	SDpnt->host = shpnt;
+	SDpnt->online = TRUE;
+
+	init_waitqueue_head(&SDpnt->device_wait);
+
+	/*
+	 * Next, hook the device to the host in question.
+	 */
+	SDpnt->prev = NULL;
+	SDpnt->next = NULL;
+	if (shpnt->host_queue != NULL) {
+		SDtail = shpnt->host_queue;
+		while (SDtail->next != NULL)
+			SDtail = SDtail->next;
+
+		SDtail->next = SDpnt;
+		SDpnt->prev = SDtail;
+	} else {
+		shpnt->host_queue = SDpnt;
+	}
+
+	/*
+	 * We need to increment the counter for this one device so we can track when
+	 * things are quiet.
+	 */
+	atomic_inc(&shpnt->host_active);
+
+	if (hardcoded == 1) {
+		Scsi_Device *oldSDpnt = SDpnt;
+		struct Scsi_Device_Template *sdtpnt;
+		channel = hchannel;
+		if (channel > shpnt->max_channel)
+			goto leave;
+		dev = hid;
+		if (dev >= shpnt->max_id)
+			goto leave;
+		lun = hlun;
+		if (lun >= shpnt->max_lun)
+			goto leave;
+		scan_scsis_single(channel, dev, lun, &max_dev_lun, &sparse_lun,
+				  &SDpnt, SCpnt, shpnt, scsi_result);
+		if (SDpnt != oldSDpnt) {
+
+			/* it could happen the blockdevice hasn't yet been inited */
+			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+				if (sdtpnt->init && sdtpnt->dev_noticed)
+					(*sdtpnt->init) ();
+
+			oldSDpnt->scsi_request_fn = NULL;
+			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+				if (sdtpnt->attach) {
+					(*sdtpnt->attach) (oldSDpnt);
+					if (oldSDpnt->attached) {
+						scsi_build_commandblocks(oldSDpnt);
+						if (0 == oldSDpnt->has_cmdblocks) {
+							printk("scan_scsis: DANGER, no command blocks\n");
+							/* What to do now ?? */
+						}
+					}
+				}
+			}
+			resize_dma_pool();
+
+			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+				if (sdtpnt->finish && sdtpnt->nr_dev) {
+					(*sdtpnt->finish) ();
+				}
+			}
+		}
+	} else {
+		/* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */
+		int order_dev;
+
+		for (channel = 0; channel <= shpnt->max_channel; channel++) {
+			for (dev = 0; dev < shpnt->max_id; ++dev) {
+				if (shpnt->reverse_ordering)
+					/* Shift to scanning 15,14,13... or 7,6,5,4, */
+					order_dev = shpnt->max_id - dev - 1;
+				else
+					order_dev = dev;
+
+				if (shpnt->this_id != order_dev) {
+
+					/*
+					 * We need the for so our continue, etc. work fine. We put this in
+					 * a variable so that we can override it during the scan if we
+					 * detect a device *KNOWN* to have multiple logical units.
+					 */
+					max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
+					 max_scsi_luns : shpnt->max_lun);
+					sparse_lun = 0;
+					for (lun = 0; lun < max_dev_lun; ++lun) {
+						if (!scan_scsis_single(channel, order_dev, lun, &max_dev_lun,
+								       &sparse_lun, &SDpnt, SCpnt, shpnt,
+							     scsi_result)
+						    && !sparse_lun)
+							break;	/* break means don't probe further for luns!=0 */
+					}	/* for lun ends */
+				}	/* if this_id != id ends */
+			}	/* for dev ends */
+		}		/* for channel ends */
+	}			/* if/else hardcoded */
+
+	/*
+	 * We need to decrement the counter for this one device
+	 * so we know when everything is quiet.
+	 */
+	atomic_dec(&shpnt->host_active);
+
+      leave:
+
+	{			/* Unchain SCpnt from host_queue */
+		Scsi_Device *prev, *next;
+		Scsi_Device *dqptr;
+
+		for (dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next)
+			continue;
+		if (dqptr) {
+			prev = dqptr->prev;
+			next = dqptr->next;
+			if (prev)
+				prev->next = next;
+			else
+				shpnt->host_queue = next;
+			if (next)
+				next->prev = prev;
 		}
-	    }
 	}
-	resize_dma_pool();
 
-        for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
-            if(sdtpnt->finish && sdtpnt->nr_dev)
-                {(*sdtpnt->finish)();}
-	}
-    }
-
-  }
-  else {
-    /* Actual LUN. PC ordering is 0->n IBM/spec ordering is n->0 */
-    int order_dev;
-    
-    for (channel = 0; channel <= shpnt->max_channel; channel++) {
-      for (dev = 0; dev < shpnt->max_id; ++dev) {
-        if( shpnt->reverse_ordering)
-        	/* Shift to scanning 15,14,13... or 7,6,5,4, */
-        	order_dev = shpnt->max_id-dev-1;
-        else
-        	order_dev = dev;
-        	
-        if (shpnt->this_id != order_dev) {
-
-          /*
-           * We need the for so our continue, etc. work fine. We put this in
-           * a variable so that we can override it during the scan if we
-           * detect a device *KNOWN* to have multiple logical units.
-           */
-          max_dev_lun = (max_scsi_luns < shpnt->max_lun ?
-                         max_scsi_luns : shpnt->max_lun);
-	  sparse_lun = 0;
-          for (lun = 0; lun < max_dev_lun; ++lun) {
-            if (!scan_scsis_single (channel, order_dev, lun, &max_dev_lun,
-				    &sparse_lun, &SDpnt, SCpnt, shpnt,
-				    scsi_result)
-		&& !sparse_lun)
-              break; /* break means don't probe further for luns!=0 */
-          }                     /* for lun ends */
-        }                       /* if this_id != id ends */
-      }                         /* for dev ends */
-    }                           /* for channel ends */
-  } 				/* if/else hardcoded */
-
-  /*
-   * We need to decrement the counter for this one device
-   * so we know when everything is quiet.
-   */
-  atomic_dec(&shpnt->host_active); 
-
-  leave:
-
-  {/* Unchain SCpnt from host_queue */
-      Scsi_Device *prev, *next;
-      Scsi_Device * dqptr;
-      
-      for(dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next) 
-          continue;
-      if(dqptr) 
-      {
-          prev = dqptr->prev;
-          next = dqptr->next;
-          if(prev)
-              prev->next = next;
-          else
-              shpnt->host_queue = next;
-          if(next) next->prev = prev;
-      }
-  }
-
-     /* Last device block does not exist.  Free memory. */
-    if (SDpnt != NULL)
-      scsi_init_free ((char *) SDpnt, sizeof (Scsi_Device));
-
-    if (SCpnt != NULL)
-      scsi_init_free ((char *) SCpnt, sizeof (Scsi_Cmnd));
-
-    /* If we allocated a buffer so we could do DMA, free it now */
-    if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-    {
-        scsi_init_free (scsi_result, 512);
-    }
-
-    {
-        Scsi_Device * sdev;
-        Scsi_Cmnd   * scmd;
-
-        SCSI_LOG_SCAN_BUS(4,printk("Host status for host %p:\n", shpnt));
-        for(sdev = shpnt->host_queue; sdev; sdev = sdev->next)
-        {
-            SCSI_LOG_SCAN_BUS(4,printk("Device %d %p: ", sdev->id, sdev));
-            for(scmd=sdev->device_queue; scmd; scmd = scmd->next)
-            {
-                SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd));
-            }
-            SCSI_LOG_SCAN_BUS(4,printk("\n"));
-        }
-    }
+	/* Last device block does not exist.  Free memory. */
+	if (SDpnt != NULL)
+		scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
+
+	if (SCpnt != NULL)
+		scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
+
+	/* If we allocated a buffer so we could do DMA, free it now */
+	if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {
+		scsi_init_free(scsi_result, 512);
+	} {
+		Scsi_Device *sdev;
+		Scsi_Cmnd *scmd;
+
+		SCSI_LOG_SCAN_BUS(4, printk("Host status for host %p:\n", shpnt));
+		for (sdev = shpnt->host_queue; sdev; sdev = sdev->next) {
+			SCSI_LOG_SCAN_BUS(4, printk("Device %d %p: ", sdev->id, sdev));
+			for (scmd = sdev->device_queue; scmd; scmd = scmd->next) {
+				SCSI_LOG_SCAN_BUS(4, printk("%p ", scmd));
+			}
+			SCSI_LOG_SCAN_BUS(4, printk("\n"));
+		}
+	}
 }
 
 /*
@@ -670,334 +674,321 @@
  * Returning 0 means Please don't ask further for lun!=0, 1 means OK go on.
  * Global variables used : scsi_devices(linked list)
  */
-int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
-    int *sparse_lun, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt,
-    struct Scsi_Host * shpnt, char *scsi_result)
-{
-  unsigned char scsi_cmd[12];
-  struct Scsi_Device_Template *sdtpnt;
-  Scsi_Device * SDtail, *SDpnt=*SDpnt2;
-  int bflags, type=-1;
-
-  SDpnt->host = shpnt;
-  SDpnt->id = dev;
-  SDpnt->lun = lun;
-  SDpnt->channel = channel;
-  SDpnt->online = TRUE;
-
-  /* Some low level driver could use device->type (DB) */
-  SDpnt->type = -1;
-
-  /*
-   * Assume that the device will have handshaking problems, and then fix this
-   * field later if it turns out it doesn't
-   */
-  SDpnt->borken = 1;
-  SDpnt->was_reset = 0;
-  SDpnt->expecting_cc_ua = 0;
-
-  scsi_cmd[0] = TEST_UNIT_READY;
-  scsi_cmd[1] = lun << 5;
-  scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
-
-  SCpnt->host = SDpnt->host;
-  SCpnt->device = SDpnt;
-  SCpnt->target = SDpnt->id;
-  SCpnt->lun = SDpnt->lun;
-  SCpnt->channel = SDpnt->channel;
-  {
-    DECLARE_MUTEX_LOCKED(sem);
-    SCpnt->request.sem = &sem;
-    SCpnt->request.rq_status = RQ_SCSI_BUSY;
-    spin_lock_irq(&io_request_lock);
-    scsi_do_cmd (SCpnt, (void *) scsi_cmd,
-                 (void *) NULL,
-                 0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
-    spin_unlock_irq(&io_request_lock);
-    down (&sem);
-    SCpnt->request.sem = NULL;
-  }
-
-  SCSI_LOG_SCAN_BUS(3,  printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
-          dev, lun, SCpnt->result));
-  SCSI_LOG_SCAN_BUS(3,print_driverbyte(SCpnt->result));
-  SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result));
-  SCSI_LOG_SCAN_BUS(3,printk("\n"));
-
-  if (SCpnt->result) {
-    if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
-         (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
-        ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
-      if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
-          ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
-          ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))
-        return 1;
-    }
-    else
-      return 0;
-  }
-
-  SCSI_LOG_SCAN_BUS(3,printk ("scsi: performing INQUIRY\n"));
-  /*
-   * Build an INQUIRY command block.
-   */
-  scsi_cmd[0] = INQUIRY;
-  scsi_cmd[1] = (lun << 5) & 0xe0;
-  scsi_cmd[2] = 0;
-  scsi_cmd[3] = 0;
-  scsi_cmd[4] = 255;
-  scsi_cmd[5] = 0;
-  SCpnt->cmd_len = 0;
-  {
-    DECLARE_MUTEX_LOCKED(sem);
-    SCpnt->request.sem = &sem;
-    SCpnt->request.rq_status = RQ_SCSI_BUSY;
-    spin_lock_irq(&io_request_lock);
-    scsi_do_cmd (SCpnt, (void *) scsi_cmd,
-                 (void *) scsi_result,
-                 256, scan_scsis_done, SCSI_TIMEOUT, 3);
-    spin_unlock_irq(&io_request_lock);
-    down (&sem);
-    SCpnt->request.sem = NULL;
-  }
-
-  SCSI_LOG_SCAN_BUS(3,printk ("scsi: INQUIRY %s with code 0x%x\n",
-                              SCpnt->result ? "failed" : "successful", SCpnt->result));
-
-  if (SCpnt->result)
-    return 0;     /* assume no peripheral if any sort of error */
-
-  /*
-   * Check the peripheral qualifier field - this tells us whether LUNS
-   * are supported here or not.
-   */
-  if( (scsi_result[0] >> 5) == 3 )
-    {
-      return 0;     /* assume no peripheral if any sort of error */
-    }
-
-  /*
-   * It would seem some TOSHIBA CDROM gets things wrong
-   */
-  if (!strncmp (scsi_result + 8, "TOSHIBA", 7) &&
-      !strncmp (scsi_result + 16, "CD-ROM", 6) &&
-      scsi_result[0] == TYPE_DISK) {
-    scsi_result[0] = TYPE_ROM;
-    scsi_result[1] |= 0x80;     /* removable */
-  }
-
-  memcpy (SDpnt->vendor, scsi_result + 8, 8);
-  memcpy (SDpnt->model, scsi_result + 16, 16);
-  memcpy (SDpnt->rev, scsi_result + 32, 4);
-
-  SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
-  SDpnt->online = TRUE;
-  SDpnt->lockable = SDpnt->removable;
-  SDpnt->changed = 0;
-  SDpnt->access_count = 0;
-  SDpnt->busy = 0;
-  SDpnt->has_cmdblocks = 0;
-  /*
-   * Currently, all sequential devices are assumed to be tapes, all random
-   * devices disk, with the appropriate read only flags set for ROM / WORM
-   * treated as RO.
-   */
-  switch (type = (scsi_result[0] & 0x1f)) {
-  case TYPE_TAPE:
-  case TYPE_DISK:
-  case TYPE_MOD:
-  case TYPE_PROCESSOR:
-  case TYPE_SCANNER:
-  case TYPE_MEDIUM_CHANGER:
-  case TYPE_ENCLOSURE:
-    SDpnt->writeable = 1;
-    break;
-  case TYPE_WORM:
-  case TYPE_ROM:
-    SDpnt->writeable = 0;
-    break;
-  default:
-    printk ("scsi: unknown type %d\n", type);
-  }
-
-  SDpnt->device_blocked = FALSE;
-  SDpnt->device_busy = 0;
-  SDpnt->single_lun = 0;
-  SDpnt->soft_reset =
-    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
-  SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
-  SDpnt->type = (type & 0x1f);
-
-  print_inquiry (scsi_result);
-
-  for (sdtpnt = scsi_devicelist; sdtpnt;
-       sdtpnt = sdtpnt->next)
-    if (sdtpnt->detect)
-      SDpnt->attached +=
-        (*sdtpnt->detect) (SDpnt);
-
-  SDpnt->scsi_level = scsi_result[2] & 0x07;
-  if (SDpnt->scsi_level >= 2 ||
-      (SDpnt->scsi_level == 1 &&
-       (scsi_result[3] & 0x0f) == 1))
-    SDpnt->scsi_level++;
-
-  /*
-   * Accommodate drivers that want to sleep when they should be in a polling
-   * loop.
-   */
-  SDpnt->disconnect = 0;
-
-  /*
-   * Get any flags for this device.
-   */
-  bflags = get_device_flags (scsi_result);
-
-  /*
-   * Set the tagged_queue flag for SCSI-II devices that purport to support
-   * tagged queuing in the INQUIRY data.
-   */
-  SDpnt->tagged_queue = 0;
-  if ((SDpnt->scsi_level >= SCSI_2) &&
-      (scsi_result[7] & 2) &&
-      !(bflags & BLIST_NOTQ)) {
-    SDpnt->tagged_supported = 1;
-    SDpnt->current_tag = 0;
-  }
-
-  /*
-   * Some revisions of the Texel CD ROM drives have handshaking problems when
-   * used with the Seagate controllers.  Before we know what type of device
-   * we're talking to, we assume it's borken and then change it here if it
-   * turns out that it isn't a TEXEL drive.
-   */
-  if ((bflags & BLIST_BORKEN) == 0)
-    SDpnt->borken = 0;
-
-  /*
-   * If we want to only allow I/O to one of the luns attached to this device
-   * at a time, then we set this flag.
-   */
-  if (bflags & BLIST_SINGLELUN)
-    SDpnt->single_lun = 1;
-
-  /*
-   * These devices need this "key" to unlock the devices so we can use it
-   */
-  if ((bflags & BLIST_KEY) != 0) {
-    printk ("Unlocked floptical drive.\n");
-    SDpnt->lockable = 0;
-    scsi_cmd[0] = MODE_SENSE;
-    scsi_cmd[1] = (lun << 5) & 0xe0;
-    scsi_cmd[2] = 0x2e;
-    scsi_cmd[3] = 0;
-    scsi_cmd[4] = 0x2a;
-    scsi_cmd[5] = 0;
-    SCpnt->cmd_len = 0;
-    {
-      DECLARE_MUTEX_LOCKED(sem);
-      SCpnt->request.rq_status = RQ_SCSI_BUSY;
-      SCpnt->request.sem = &sem;
-      spin_lock_irq(&io_request_lock);
-      scsi_do_cmd (SCpnt, (void *) scsi_cmd,
-                   (void *) scsi_result, 0x2a,
-                   scan_scsis_done, SCSI_TIMEOUT, 3);
-      spin_unlock_irq(&io_request_lock);
-      down (&sem);
-      SCpnt->request.sem = NULL;
-    }
-  }
-
-  /*
-   * Detach the command from the device. It was just a temporary to be used while
-   * scanning the bus - the real ones will be allocated later.
-   */
-  SDpnt->device_queue = NULL;
-
-  /*
-   * This device was already hooked up to the host in question,
-   * so at this point we just let go of it and it should be fine.  We do need to
-   * allocate a new one and attach it to the host so that we can further scan the bus.
-   */
-  SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
-  *SDpnt2=SDpnt;
-  if (!SDpnt)
-  {
-      printk ("scsi: scan_scsis_single: Cannot malloc\n");
-      return 0;
-  }
-
-  /*
-   * And hook up our command block to the new device we will be testing
-   * for.
-   */
-  SDpnt->device_queue = SCpnt;
-  SDpnt->online = TRUE;
-
-  init_waitqueue_head(&SDpnt->device_wait);
-
-  /*
-   * Since we just found one device, there had damn well better be one in the list
-   * already.
-   */
-  if( shpnt->host_queue == NULL )
-      panic("scan_scsis_single: Host queue == NULL\n");
-
-  SDtail = shpnt->host_queue;
-  while (SDtail->next)
-  {
-      SDtail = SDtail->next;
-  }
-
-  /* Add this device to the linked list at the end */
-  SDtail->next = SDpnt;
-  SDpnt->prev = SDtail;
-  SDpnt->next = NULL;
-
-  /*
-   * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
-   */
-  if (bflags & BLIST_NOLUN)
-    return 0;                   /* break; */
-
-  /*
-   * If this device is known to support sparse multiple units, override the
-   * other settings, and scan all of them.
-   */
-  if (bflags & BLIST_SPARSELUN) {
-    *max_dev_lun = 8;
-    *sparse_lun = 1;
-    return 1;
-  }
-
-  /*
-   * If this device is known to support multiple units, override the other
-   * settings, and scan all of them.
-   */
-  if (bflags & BLIST_FORCELUN) {
-    *max_dev_lun = 8;
-    return 1;
-  }
-
-  /*
-   * REGAL CDC-4X: avoid hang after LUN 4
-   */
-  if (bflags & BLIST_MAX5LUN) {
-    *max_dev_lun = 5;
-    return 1;
-  }
-
-  /*
-   * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
-   * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
-   * (ANSI SCSI Revision 1) and Response Data Format 0
-   */
-  if (((scsi_result[2] & 0x07) == 0)
-      ||
-      ((scsi_result[2] & 0x07) == 1 &&
-       (scsi_result[3] & 0x0f) == 0))
-    return 0;
-  return 1;
+int scan_scsis_single(int channel, int dev, int lun, int *max_dev_lun,
+	       int *sparse_lun, Scsi_Device ** SDpnt2, Scsi_Cmnd * SCpnt,
+		      struct Scsi_Host *shpnt, char *scsi_result)
+{
+	unsigned char scsi_cmd[12];
+	struct Scsi_Device_Template *sdtpnt;
+	Scsi_Device *SDtail, *SDpnt = *SDpnt2;
+	int bflags, type = -1;
+
+	SDpnt->host = shpnt;
+	SDpnt->id = dev;
+	SDpnt->lun = lun;
+	SDpnt->channel = channel;
+	SDpnt->online = TRUE;
+
+	/* Some low level driver could use device->type (DB) */
+	SDpnt->type = -1;
+
+	/*
+	 * Assume that the device will have handshaking problems, and then fix this
+	 * field later if it turns out it doesn't
+	 */
+	SDpnt->borken = 1;
+	SDpnt->was_reset = 0;
+	SDpnt->expecting_cc_ua = 0;
+
+	scsi_cmd[0] = TEST_UNIT_READY;
+	scsi_cmd[1] = lun << 5;
+	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+
+	SCpnt->host = SDpnt->host;
+	SCpnt->device = SDpnt;
+	SCpnt->target = SDpnt->id;
+	SCpnt->lun = SDpnt->lun;
+	SCpnt->channel = SDpnt->channel;
+	{
+		DECLARE_MUTEX_LOCKED(sem);
+		SCpnt->request.sem = &sem;
+		SCpnt->request.rq_status = RQ_SCSI_BUSY;
+		spin_lock_irq(&io_request_lock);
+		scsi_do_cmd(SCpnt, (void *) scsi_cmd,
+			    (void *) NULL,
+			    0, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+		spin_unlock_irq(&io_request_lock);
+		down(&sem);
+		SCpnt->request.sem = NULL;
+	}
+
+	SCSI_LOG_SCAN_BUS(3, printk("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
+				    dev, lun, SCpnt->result));
+	SCSI_LOG_SCAN_BUS(3, print_driverbyte(SCpnt->result));
+	SCSI_LOG_SCAN_BUS(3, print_hostbyte(SCpnt->result));
+	SCSI_LOG_SCAN_BUS(3, printk("\n"));
+
+	if (SCpnt->result) {
+		if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
+		     (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
+		    ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
+			if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+			    ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+			    ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST || lun > 0))
+				return 1;
+		} else
+			return 0;
+	}
+	SCSI_LOG_SCAN_BUS(3, printk("scsi: performing INQUIRY\n"));
+	/*
+	 * Build an INQUIRY command block.
+	 */
+	scsi_cmd[0] = INQUIRY;
+	scsi_cmd[1] = (lun << 5) & 0xe0;
+	scsi_cmd[2] = 0;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SCpnt->cmd_len = 0;
+	{
+		DECLARE_MUTEX_LOCKED(sem);
+		SCpnt->request.sem = &sem;
+		SCpnt->request.rq_status = RQ_SCSI_BUSY;
+		spin_lock_irq(&io_request_lock);
+		scsi_do_cmd(SCpnt, (void *) scsi_cmd,
+			    (void *) scsi_result,
+			    256, scan_scsis_done, SCSI_TIMEOUT, 3);
+		spin_unlock_irq(&io_request_lock);
+		down(&sem);
+		SCpnt->request.sem = NULL;
+	}
+
+	SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n",
+		SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+	if (SCpnt->result)
+		return 0;	/* assume no peripheral if any sort of error */
+
+	/*
+	 * Check the peripheral qualifier field - this tells us whether LUNS
+	 * are supported here or not.
+	 */
+	if ((scsi_result[0] >> 5) == 3) {
+		return 0;	/* assume no peripheral if any sort of error */
+	}
+	/*
+	 * It would seem some TOSHIBA CDROM gets things wrong
+	 */
+	if (!strncmp(scsi_result + 8, "TOSHIBA", 7) &&
+	    !strncmp(scsi_result + 16, "CD-ROM", 6) &&
+	    scsi_result[0] == TYPE_DISK) {
+		scsi_result[0] = TYPE_ROM;
+		scsi_result[1] |= 0x80;		/* removable */
+	}
+	memcpy(SDpnt->vendor, scsi_result + 8, 8);
+	memcpy(SDpnt->model, scsi_result + 16, 16);
+	memcpy(SDpnt->rev, scsi_result + 32, 4);
+
+	SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+	SDpnt->online = TRUE;
+	SDpnt->lockable = SDpnt->removable;
+	SDpnt->changed = 0;
+	SDpnt->access_count = 0;
+	SDpnt->busy = 0;
+	SDpnt->has_cmdblocks = 0;
+	/*
+	 * Currently, all sequential devices are assumed to be tapes, all random
+	 * devices disk, with the appropriate read only flags set for ROM / WORM
+	 * treated as RO.
+	 */
+	switch (type = (scsi_result[0] & 0x1f)) {
+	case TYPE_TAPE:
+	case TYPE_DISK:
+	case TYPE_MOD:
+	case TYPE_PROCESSOR:
+	case TYPE_SCANNER:
+	case TYPE_MEDIUM_CHANGER:
+	case TYPE_ENCLOSURE:
+		SDpnt->writeable = 1;
+		break;
+	case TYPE_WORM:
+	case TYPE_ROM:
+		SDpnt->writeable = 0;
+		break;
+	default:
+		printk("scsi: unknown type %d\n", type);
+	}
+
+	SDpnt->device_blocked = FALSE;
+	SDpnt->device_busy = 0;
+	SDpnt->single_lun = 0;
+	SDpnt->soft_reset =
+	    (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
+	SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
+	SDpnt->type = (type & 0x1f);
+
+	print_inquiry(scsi_result);
+
+	for (sdtpnt = scsi_devicelist; sdtpnt;
+	     sdtpnt = sdtpnt->next)
+		if (sdtpnt->detect)
+			SDpnt->attached +=
+			    (*sdtpnt->detect) (SDpnt);
+
+	SDpnt->scsi_level = scsi_result[2] & 0x07;
+	if (SDpnt->scsi_level >= 2 ||
+	    (SDpnt->scsi_level == 1 &&
+	     (scsi_result[3] & 0x0f) == 1))
+		SDpnt->scsi_level++;
+
+	/*
+	 * Accommodate drivers that want to sleep when they should be in a polling
+	 * loop.
+	 */
+	SDpnt->disconnect = 0;
+
+	/*
+	 * Get any flags for this device.
+	 */
+	bflags = get_device_flags(scsi_result);
+
+	/*
+	 * Set the tagged_queue flag for SCSI-II devices that purport to support
+	 * tagged queuing in the INQUIRY data.
+	 */
+	SDpnt->tagged_queue = 0;
+	if ((SDpnt->scsi_level >= SCSI_2) &&
+	    (scsi_result[7] & 2) &&
+	    !(bflags & BLIST_NOTQ)) {
+		SDpnt->tagged_supported = 1;
+		SDpnt->current_tag = 0;
+	}
+	/*
+	 * Some revisions of the Texel CD ROM drives have handshaking problems when
+	 * used with the Seagate controllers.  Before we know what type of device
+	 * we're talking to, we assume it's borken and then change it here if it
+	 * turns out that it isn't a TEXEL drive.
+	 */
+	if ((bflags & BLIST_BORKEN) == 0)
+		SDpnt->borken = 0;
+
+	/*
+	 * If we want to only allow I/O to one of the luns attached to this device
+	 * at a time, then we set this flag.
+	 */
+	if (bflags & BLIST_SINGLELUN)
+		SDpnt->single_lun = 1;
+
+	/*
+	 * These devices need this "key" to unlock the devices so we can use it
+	 */
+	if ((bflags & BLIST_KEY) != 0) {
+		printk("Unlocked floptical drive.\n");
+		SDpnt->lockable = 0;
+		scsi_cmd[0] = MODE_SENSE;
+		scsi_cmd[1] = (lun << 5) & 0xe0;
+		scsi_cmd[2] = 0x2e;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = 0x2a;
+		scsi_cmd[5] = 0;
+		SCpnt->cmd_len = 0;
+		{
+			DECLARE_MUTEX_LOCKED(sem);
+			SCpnt->request.rq_status = RQ_SCSI_BUSY;
+			SCpnt->request.sem = &sem;
+			spin_lock_irq(&io_request_lock);
+			scsi_do_cmd(SCpnt, (void *) scsi_cmd,
+				    (void *) scsi_result, 0x2a,
+				    scan_scsis_done, SCSI_TIMEOUT, 3);
+			spin_unlock_irq(&io_request_lock);
+			down(&sem);
+			SCpnt->request.sem = NULL;
+		}
+	}
+	/*
+	 * Detach the command from the device. It was just a temporary to be used while
+	 * scanning the bus - the real ones will be allocated later.
+	 */
+	SDpnt->device_queue = NULL;
+
+	/*
+	 * This device was already hooked up to the host in question,
+	 * so at this point we just let go of it and it should be fine.  We do need to
+	 * allocate a new one and attach it to the host so that we can further scan the bus.
+	 */
+	SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof(Scsi_Device), GFP_ATOMIC);
+	*SDpnt2 = SDpnt;
+	if (!SDpnt) {
+		printk("scsi: scan_scsis_single: Cannot malloc\n");
+		return 0;
+	}
+	/*
+	 * And hook up our command block to the new device we will be testing
+	 * for.
+	 */
+	SDpnt->device_queue = SCpnt;
+	SDpnt->online = TRUE;
+
+	init_waitqueue_head(&SDpnt->device_wait);
+
+	/*
+	 * Since we just found one device, there had damn well better be one in the list
+	 * already.
+	 */
+	if (shpnt->host_queue == NULL)
+		panic("scan_scsis_single: Host queue == NULL\n");
+
+	SDtail = shpnt->host_queue;
+	while (SDtail->next) {
+		SDtail = SDtail->next;
+	}
+
+	/* Add this device to the linked list at the end */
+	SDtail->next = SDpnt;
+	SDpnt->prev = SDtail;
+	SDpnt->next = NULL;
+
+	/*
+	 * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+	 */
+	if (bflags & BLIST_NOLUN)
+		return 0;	/* break; */
+
+	/*
+	 * If this device is known to support sparse multiple units, override the
+	 * other settings, and scan all of them.
+	 */
+	if (bflags & BLIST_SPARSELUN) {
+		*max_dev_lun = 8;
+		*sparse_lun = 1;
+		return 1;
+	}
+	/*
+	 * If this device is known to support multiple units, override the other
+	 * settings, and scan all of them.
+	 */
+	if (bflags & BLIST_FORCELUN) {
+		*max_dev_lun = 8;
+		return 1;
+	}
+	/*
+	 * REGAL CDC-4X: avoid hang after LUN 4
+	 */
+	if (bflags & BLIST_MAX5LUN) {
+		*max_dev_lun = 5;
+		return 1;
+	}
+	/*
+	 * We assume the device can't handle lun!=0 if: - it reports scsi-0 (ANSI
+	 * SCSI Revision 0) (old drives like MAXTOR XT-3280) or - it reports scsi-1
+	 * (ANSI SCSI Revision 1) and Response Data Format 0
+	 */
+	if (((scsi_result[2] & 0x07) == 0)
+	    ||
+	    ((scsi_result[2] & 0x07) == 1 &&
+	     (scsi_result[3] & 0x0f) == 0))
+		return 0;
+	return 1;
 }
 
 /*
@@ -1017,118 +1008,125 @@
  * of the calling code to ensure that this is the case.
  */
 
-Scsi_Cmnd * scsi_request_queueable (struct request * req, Scsi_Device * device)
+Scsi_Cmnd *scsi_request_queueable(struct request * req, Scsi_Device * device)
 {
-    Scsi_Cmnd * SCpnt = NULL;
-    int tablesize;
-    Scsi_Cmnd * found = NULL;
-    struct buffer_head * bh, *bhp;
-
-    if (!device)
-	panic ("No device passed to scsi_request_queueable().\n");
-
-    if (req && req->rq_status == RQ_INACTIVE)
-	panic("Inactive in scsi_request_queueable");
-
-    /*
-     * Look for a free command block.  If we have been instructed not to queue
-     * multiple commands to multi-lun devices, then check to see what else is
-     * going for this device first.
-     */
-
-    if (!device->single_lun) {
-	SCpnt = device->device_queue;
-	while(SCpnt){
-	    if(SCpnt->request.rq_status == RQ_INACTIVE) break;
-	    SCpnt = SCpnt->next;
-	}
-    } else {
-	SCpnt = device->device_queue;
-	while(SCpnt){
-	    if(SCpnt->channel == device->channel
-                && SCpnt->target == device->id) {
-		if (SCpnt->lun == device->lun) {
-		    if(found == NULL
-		       && SCpnt->request.rq_status == RQ_INACTIVE)
-		    {
-			found=SCpnt;
-		    }
-		}
-		if(SCpnt->request.rq_status != RQ_INACTIVE) {
-		    /*
-		     * I think that we should really limit things to one
-		     * outstanding command per device - this is what tends
-                     * to trip up buggy firmware.
-		     */
-		    return NULL;
-		}
-	    }
-	    SCpnt = SCpnt->next;
-	}
-	SCpnt = found;
-    }
-
-    if (!SCpnt) return NULL;
-
-    if (SCSI_BLOCK(device, device->host)) return NULL;
-
-    if (req) {
-	memcpy(&SCpnt->request, req, sizeof(struct request));
-	tablesize = device->host->sg_tablesize;
-	bhp = bh = req->bh;
-	if(!tablesize) bh = NULL;
-	/* Take a quick look through the table to see how big it is.
-	 * We already have our copy of req, so we can mess with that
-	 * if we want to.
-	 */
-	while(req->nr_sectors && bh){
-	    bhp = bhp->b_reqnext;
-	    if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
-	    req->nr_sectors -= bh->b_size >> 9;
-	    req->sector += bh->b_size >> 9;
-	    if(!tablesize) break;
-	    bh = bhp;
-	}
-	if(req->nr_sectors && bh && bh->b_reqnext){  /* Any leftovers? */
-	    SCpnt->request.bhtail = bh;
-	    req->bh = bh->b_reqnext; /* Divide request */
-	    bh->b_reqnext = NULL;
-	    bh = req->bh;
-
-	    /* Now reset things so that req looks OK */
-	    SCpnt->request.nr_sectors -= req->nr_sectors;
-	    req->current_nr_sectors = bh->b_size >> 9;
-	    req->buffer = bh->b_data;
-	    SCpnt->request.sem = NULL; /* Wait until whole thing done */
+	Scsi_Cmnd *SCpnt = NULL;
+	int tablesize;
+	Scsi_Cmnd *found = NULL;
+	struct buffer_head *bh, *bhp;
+
+	if (!device)
+		panic("No device passed to scsi_request_queueable().\n");
+
+	if (req && req->rq_status == RQ_INACTIVE)
+		panic("Inactive in scsi_request_queueable");
+
+	/*
+	 * Look for a free command block.  If we have been instructed not to queue
+	 * multiple commands to multi-lun devices, then check to see what else is
+	 * going for this device first.
+	 */
+
+	if (!device->single_lun) {
+		SCpnt = device->device_queue;
+		while (SCpnt) {
+			if (SCpnt->request.rq_status == RQ_INACTIVE)
+				break;
+			SCpnt = SCpnt->next;
+		}
+	} else {
+		SCpnt = device->device_queue;
+		while (SCpnt) {
+			if (SCpnt->channel == device->channel
+			    && SCpnt->target == device->id) {
+				if (SCpnt->lun == device->lun) {
+					if (found == NULL
+					    && SCpnt->request.rq_status == RQ_INACTIVE) {
+						found = SCpnt;
+					}
+				}
+				if (SCpnt->request.rq_status != RQ_INACTIVE) {
+					/*
+					 * I think that we should really limit things to one
+					 * outstanding command per device - this is what tends
+					 * to trip up buggy firmware.
+					 */
+					return NULL;
+				}
+			}
+			SCpnt = SCpnt->next;
+		}
+		SCpnt = found;
+	}
+
+	if (!SCpnt)
+		return NULL;
+
+	if (SCSI_BLOCK(device, device->host))
+		return NULL;
+
+	if (req) {
+		memcpy(&SCpnt->request, req, sizeof(struct request));
+		tablesize = device->host->sg_tablesize;
+		bhp = bh = req->bh;
+		if (!tablesize)
+			bh = NULL;
+		/* Take a quick look through the table to see how big it is.
+		 * We already have our copy of req, so we can mess with that
+		 * if we want to.
+		 */
+		while (req->nr_sectors && bh) {
+			bhp = bhp->b_reqnext;
+			if (!bhp || !CONTIGUOUS_BUFFERS(bh, bhp))
+				tablesize--;
+			req->nr_sectors -= bh->b_size >> 9;
+			req->sector += bh->b_size >> 9;
+			if (!tablesize)
+				break;
+			bh = bhp;
+		}
+		if (req->nr_sectors && bh && bh->b_reqnext) {	/* Any leftovers? */
+			SCpnt->request.bhtail = bh;
+			req->bh = bh->b_reqnext;	/* Divide request */
+			bh->b_reqnext = NULL;
+			bh = req->bh;
+
+			/* Now reset things so that req looks OK */
+			SCpnt->request.nr_sectors -= req->nr_sectors;
+			req->current_nr_sectors = bh->b_size >> 9;
+			req->buffer = bh->b_data;
+			SCpnt->request.sem = NULL;	/* Wait until whole thing done */
+		} else {
+			req->rq_status = RQ_INACTIVE;
+			wake_up(&wait_for_request);
+		}
 	} else {
-	    req->rq_status = RQ_INACTIVE;
-	    wake_up(&wait_for_request);
+		SCpnt->request.rq_status = RQ_SCSI_BUSY;	/* Busy, but no request */
+		SCpnt->request.sem = NULL;	/* And no one is waiting for the device
+						 * either */
 	}
-    } else {
-	SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Busy, but no request */
-	SCpnt->request.sem = NULL;   /* And no one is waiting for the device
-				      * either */
-    }
-
-    atomic_inc(&SCpnt->host->host_active); 
-    SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,
-                               atomic_read(&SCpnt->host->host_active)));
-    SCpnt->use_sg = 0;               /* Reset the scatter-gather flag */
-    SCpnt->old_use_sg  = 0;
-    SCpnt->transfersize = 0;
-    SCpnt->underflow = 0;
-    SCpnt->cmd_len = 0;
-
-/* Since not everyone seems to set the device info correctly
- * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
- */
-    SCpnt->channel = device->channel;
-    SCpnt->lun = device->lun;
-    SCpnt->target = device->id;
-    SCpnt->state = SCSI_STATE_INITIALIZING;
-    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
 
-    return SCpnt;
+	atomic_inc(&SCpnt->host->host_active);
+	SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,
+				atomic_read(&SCpnt->host->host_active)));
+	SCpnt->use_sg = 0;	/* Reset the scatter-gather flag */
+	SCpnt->old_use_sg = 0;
+	SCpnt->transfersize = 0;
+	SCpnt->underflow = 0;
+	SCpnt->cmd_len = 0;
+
+	/*
+	 *	Since not everyone seems to set the device info correctly
+	 *	before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+	 */
+	
+	SCpnt->channel = device->channel;
+	SCpnt->lun = device->lun;
+	SCpnt->target = device->id;
+	SCpnt->state = SCSI_STATE_INITIALIZING;
+	SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
+
+	return SCpnt;
 }
 
 /* This function returns a structure pointer that will be valid for
@@ -1141,156 +1139,164 @@
  * of the packets for each device
  */
 
-Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
-			     int wait)
+Scsi_Cmnd *scsi_allocate_device(struct request ** reqp, Scsi_Device * device,
+				int wait)
 {
-    kdev_t dev;
-    struct request * req = NULL;
-    int tablesize;
-    struct buffer_head * bh, *bhp;
-    struct Scsi_Host * host;
-    Scsi_Cmnd * SCpnt = NULL;
-    Scsi_Cmnd * SCwait = NULL;
-    Scsi_Cmnd * found = NULL;
-
-    if (!device)
-	panic ("No device passed to scsi_allocate_device().\n");
-
-    if (reqp) req = *reqp;
-
-    /* See if this request has already been queued by an interrupt routine */
-    if (req) {
-	if(req->rq_status == RQ_INACTIVE) return NULL;
-	dev = req->rq_dev;
-    } else
-        dev = 0;		/* unused */
+	kdev_t dev;
+	struct request *req = NULL;
+	int tablesize;
+	struct buffer_head *bh, *bhp;
+	struct Scsi_Host *host;
+	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Cmnd *SCwait = NULL;
+	Scsi_Cmnd *found = NULL;
 
-    host = device->host;
+	if (!device)
+		panic("No device passed to scsi_allocate_device().\n");
 
-    if (in_interrupt() && SCSI_BLOCK(device, host)) return NULL;
+	if (reqp)
+		req = *reqp;
 
-    while (1==1){
-	if (!device->single_lun) {
-	    SCpnt = device->device_queue;
-	    while(SCpnt){
-		SCwait = SCpnt;
-		if(SCpnt->request.rq_status == RQ_INACTIVE) break;
-		SCpnt = SCpnt->next;
-	    }
-	} else {
-	    SCpnt = device->device_queue;
-	    while(SCpnt){
-		if(SCpnt->channel == device->channel
-                   && SCpnt->target == device->id) {
-		    if (SCpnt->lun == device->lun) {
-			SCwait = SCpnt;
-			if(found == NULL
-			   && SCpnt->request.rq_status == RQ_INACTIVE)
-			{
-			    found=SCpnt;
+	/*
+	 * See if this request has already been queued by an 
+	 * interrupt routine 
+	 */
+	 
+	if (req) {
+		if (req->rq_status == RQ_INACTIVE)
+			return NULL;
+		dev = req->rq_dev;
+	} else
+		dev = 0;	/* unused */
+
+	host = device->host;
+
+	if (in_interrupt() && SCSI_BLOCK(device, host))
+		return NULL;
+
+	while (1 == 1) {
+		if (!device->single_lun) {
+			SCpnt = device->device_queue;
+			while (SCpnt) {
+				SCwait = SCpnt;
+				if (SCpnt->request.rq_status == RQ_INACTIVE)
+					break;
+				SCpnt = SCpnt->next;
 			}
-		    }
-		    if(SCpnt->request.rq_status != RQ_INACTIVE) {
-			/*
-			 * I think that we should really limit things to one
-			 * outstanding command per device - this is what tends
-                         * to trip up buggy firmware.
-			 */
-			found = NULL;
-			break;
-		    }
+		} else {
+			SCpnt = device->device_queue;
+			while (SCpnt) {
+				if (SCpnt->channel == device->channel
+				    && SCpnt->target == device->id) {
+					if (SCpnt->lun == device->lun) {
+						SCwait = SCpnt;
+						if (found == NULL
+						    && SCpnt->request.rq_status == RQ_INACTIVE) {
+							found = SCpnt;
+						}
+					}
+					if (SCpnt->request.rq_status != RQ_INACTIVE) {
+						/*
+						 * I think that we should really limit things to one
+						 * outstanding command per device - this is what tends
+						 * to trip up buggy firmware.
+						 */
+						found = NULL;
+						break;
+					}
+				}
+				SCpnt = SCpnt->next;
+			}
+			SCpnt = found;
 		}
-		SCpnt = SCpnt->next;
-	    }
-	    SCpnt = found;
-	}
 
-	/* See if this request has already been queued by an interrupt routine
-	 */
-	if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {
-	    return NULL;
-	}
-	if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE)	/* Might have changed */
-	{
-		if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
-			spin_unlock(&io_request_lock);		/* FIXME!!!! */
- 			sleep_on(&device->device_wait);
- 			spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
-	 	} else {
-	 		if (!wait) return NULL;
- 			if (!SCwait) {
-	 			printk("Attempt to allocate device channel %d,"
-                                       " target %d, lun %d\n", device->channel,
-                                       device->id, device->lun);
- 				panic("No device found in scsi_allocate_device\n");
-	 		}
- 		}
-	} else {
-	    if (req) {
-		memcpy(&SCpnt->request, req, sizeof(struct request));
-		tablesize = device->host->sg_tablesize;
-		bhp = bh = req->bh;
-		if(!tablesize) bh = NULL;
-		/* Take a quick look through the table to see how big it is.
-		 * We already have our copy of req, so we can mess with that
-		 * if we want to.
+		/* See if this request has already been queued by an interrupt routine
 		 */
-		while(req->nr_sectors && bh){
-		    bhp = bhp->b_reqnext;
-		    if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
-		    req->nr_sectors -= bh->b_size >> 9;
-		    req->sector += bh->b_size >> 9;
-		    if(!tablesize) break;
-		    bh = bhp;
-		}
-		if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */
-		    SCpnt->request.bhtail = bh;
-		    req->bh = bh->b_reqnext; /* Divide request */
-		    bh->b_reqnext = NULL;
-		    bh = req->bh;
-		    /* Now reset things so that req looks OK */
-		    SCpnt->request.nr_sectors -= req->nr_sectors;
-		    req->current_nr_sectors = bh->b_size >> 9;
-		    req->buffer = bh->b_data;
-		    SCpnt->request.sem = NULL; /* Wait until whole thing done*/
+		if (req && (req->rq_status == RQ_INACTIVE || req->rq_dev != dev)) {
+			return NULL;
 		}
-		else
-		{
-		    req->rq_status = RQ_INACTIVE;
-		    *reqp = req->next;
-		    wake_up(&wait_for_request);
+		if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) {	/* Might have changed */
+			if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE) {
+				spin_unlock(&io_request_lock);	/* FIXME!!!! */
+				sleep_on(&device->device_wait);
+				spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
+			} else {
+				if (!wait)
+					return NULL;
+				if (!SCwait) {
+					printk("Attempt to allocate device channel %d,"
+					       " target %d, lun %d\n", device->channel,
+					       device->id, device->lun);
+					panic("No device found in scsi_allocate_device\n");
+				}
+			}
+		} else {
+			if (req) {
+				memcpy(&SCpnt->request, req, sizeof(struct request));
+				tablesize = device->host->sg_tablesize;
+				bhp = bh = req->bh;
+				if (!tablesize)
+					bh = NULL;
+				/* Take a quick look through the table to see how big it is.
+				 * We already have our copy of req, so we can mess with that
+				 * if we want to.
+				 */
+				while (req->nr_sectors && bh) {
+					bhp = bhp->b_reqnext;
+					if (!bhp || !CONTIGUOUS_BUFFERS(bh, bhp))
+						tablesize--;
+					req->nr_sectors -= bh->b_size >> 9;
+					req->sector += bh->b_size >> 9;
+					if (!tablesize)
+						break;
+					bh = bhp;
+				}
+				if (req->nr_sectors && bh && bh->b_reqnext) {	/* Any leftovers? */
+					SCpnt->request.bhtail = bh;
+					req->bh = bh->b_reqnext;	/* Divide request */
+					bh->b_reqnext = NULL;
+					bh = req->bh;
+					/* Now reset things so that req looks OK */
+					SCpnt->request.nr_sectors -= req->nr_sectors;
+					req->current_nr_sectors = bh->b_size >> 9;
+					req->buffer = bh->b_data;
+					SCpnt->request.sem = NULL;	/* Wait until whole thing done */
+				} else {
+					req->rq_status = RQ_INACTIVE;
+					*reqp = req->next;
+					wake_up(&wait_for_request);
+				}
+			} else {
+				SCpnt->request.rq_status = RQ_SCSI_BUSY;
+				SCpnt->request.sem = NULL;	/* And no one is waiting for this
+								 * to complete */
+			}
+			atomic_inc(&SCpnt->host->host_active);
+			SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
+						   SCpnt->target,
+				atomic_read(&SCpnt->host->host_active)));
+			break;
 		}
-	    } else {
-		SCpnt->request.rq_status = RQ_SCSI_BUSY;
-		SCpnt->request.sem = NULL;   /* And no one is waiting for this
-					      * to complete */
-	    }
-            atomic_inc(&SCpnt->host->host_active); 
-            SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", 
-                                       SCpnt->target,
-                                       atomic_read(&SCpnt->host->host_active)));
-	    break;
-	}
-    }
-
-    SCpnt->use_sg = 0;            /* Reset the scatter-gather flag */
-    SCpnt->old_use_sg  = 0;
-    SCpnt->transfersize = 0;      /* No default transfer size */
-    SCpnt->cmd_len = 0;
-
-    SCpnt->underflow = 0;         /* Do not flag underflow conditions */
-
-    /* Since not everyone seems to set the device info correctly
-     * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
-     * FIXME(eric) This doesn't make any sense.
-     */
-    SCpnt->channel = device->channel;
-    SCpnt->lun = device->lun;
-    SCpnt->target = device->id;
-    SCpnt->state = SCSI_STATE_INITIALIZING;
-    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
+	}
+
+	SCpnt->use_sg = 0;	/* Reset the scatter-gather flag */
+	SCpnt->old_use_sg = 0;
+	SCpnt->transfersize = 0;	/* No default transfer size */
+	SCpnt->cmd_len = 0;
+
+	SCpnt->underflow = 0;	/* Do not flag underflow conditions */
+
+	/* Since not everyone seems to set the device info correctly
+	 * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+	 * FIXME(eric) This doesn't make any sense.
+	 */
+	SCpnt->channel = device->channel;
+	SCpnt->lun = device->lun;
+	SCpnt->target = device->id;
+	SCpnt->state = SCSI_STATE_INITIALIZING;
+	SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
 
-    return SCpnt;
+	return SCpnt;
 }
 
 /*
@@ -1304,159 +1310,144 @@
  *              this funciton is called.  This is in effect the inverse
  *              of scsi_allocate_device/scsi_request_queueable.
  */
-void
-scsi_release_command(Scsi_Cmnd * SCpnt)
+void scsi_release_command(Scsi_Cmnd * SCpnt)
 {
-  SCpnt->request.rq_status = RQ_INACTIVE;
-  SCpnt->state = SCSI_STATE_UNUSED;
-  SCpnt->owner = SCSI_OWNER_NOBODY;
-  atomic_dec(&SCpnt->host->host_active); 
-
-  SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n", 
-                             SCpnt->target,
-                             atomic_read(&SCpnt->host->host_active),
-                             SCpnt->host->host_failed));
-  if( SCpnt->host->host_failed != 0 )
-    {
-      SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n", 
-                                 SCpnt->host->in_recovery,
-                                 SCpnt->host->eh_active));
-    }
-
-  /*
-   * If the host is having troubles, then look to see if this was the last
-   * command that might have failed.  If so, wake up the error handler.
-   */
-  if( SCpnt->host->in_recovery
-      && !SCpnt->host->eh_active
-      && SCpnt->host->host_busy == SCpnt->host->host_failed )
-  {
-      SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
-                                 atomic_read(&SCpnt->host->eh_wait->count)));
-      up(SCpnt->host->eh_wait);
-  }
+	SCpnt->request.rq_status = RQ_INACTIVE;
+	SCpnt->state = SCSI_STATE_UNUSED;
+	SCpnt->owner = SCSI_OWNER_NOBODY;
+	atomic_dec(&SCpnt->host->host_active);
+
+	SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n",
+				   SCpnt->target,
+				   atomic_read(&SCpnt->host->host_active),
+				   SCpnt->host->host_failed));
+	if (SCpnt->host->host_failed != 0) {
+		SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n",
+						SCpnt->host->in_recovery,
+						SCpnt->host->eh_active));
+	}
+	/*
+	 * If the host is having troubles, then look to see if this was the last
+	 * command that might have failed.  If so, wake up the error handler.
+	 */
+	if (SCpnt->host->in_recovery
+	    && !SCpnt->host->eh_active
+	    && SCpnt->host->host_busy == SCpnt->host->host_failed) {
+		SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
+			     atomic_read(&SCpnt->host->eh_wait->count)));
+		up(SCpnt->host->eh_wait);
+	}
 }
 
 /*
  * This is inline because we have stack problemes if we recurse to deeply.
  */
 
-inline int internal_cmnd (Scsi_Cmnd * SCpnt)
+inline int internal_cmnd(Scsi_Cmnd * SCpnt)
 {
 #ifdef DEBUG_DELAY
-    unsigned long clock;
+	unsigned long clock;
 #endif
-    struct Scsi_Host   * host;
-    int                  rtn = 0;
-    unsigned long        timeout;
+	struct Scsi_Host *host;
+	int rtn = 0;
+	unsigned long timeout;
 
 #if DEBUG
-    unsigned long *ret = 0;
+	unsigned long *ret = 0;
 #ifdef __mips__
-    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
+	__asm__ __volatile__("move\t%0,$31":"=r"(ret));
 #else
-   ret =  __builtin_return_address(0);
+	ret = __builtin_return_address(0);
 #endif
 #endif
 
-    host = SCpnt->host;
+	host = SCpnt->host;
+
+	/* Assign a unique nonzero serial_number. */
+	if (++serial_number == 0)
+		serial_number = 1;
+	SCpnt->serial_number = serial_number;
+
+	/*
+	 * We will wait MIN_RESET_DELAY clock ticks after the last reset so
+	 * we can avoid the drive not being ready.
+	 */
+	timeout = host->last_reset + MIN_RESET_DELAY;
+
+	if (host->resetting && time_before(jiffies, timeout)) {
+		int ticks_remaining = timeout - jiffies;
+		/*
+		 * NOTE: This may be executed from within an interrupt
+		 * handler!  This is bad, but for now, it'll do.  The irq
+		 * level of the interrupt handler has been masked out by the
+		 * platform dependent interrupt handling code already, so the
+		 * sti() here will not cause another call to the SCSI host's
+		 * interrupt handler (assuming there is one irq-level per
+		 * host).
+		 */
+		spin_unlock_irq(&io_request_lock);
+		while (--ticks_remaining >= 0)
+			mdelay(1 + 999 / HZ);
+		host->resetting = 0;
+		spin_lock_irq(&io_request_lock);
+	}
+	if (host->hostt->use_new_eh_code) {
+		scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
+	} else {
+		scsi_add_timer(SCpnt, SCpnt->timeout_per_command,
+			       scsi_old_times_out);
+	}
+
+	/*
+	 * We will use a queued command if possible, otherwise we will emulate the
+	 * queuing and calling of completion function ourselves.
+	 */
+	SCSI_LOG_MLQUEUE(3, printk("internal_cmnd (host = %d, channel = %d, target = %d, "
+	       "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
+	SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
+			    SCpnt->buffer, SCpnt->bufflen, SCpnt->done));
+
+	SCpnt->state = SCSI_STATE_QUEUED;
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	if (host->can_queue) {
+		SCSI_LOG_MLQUEUE(3, printk("queuecommand : routine at %p\n",
+					   host->hostt->queuecommand));
+		/*
+		 * Use the old error handling code if we haven't converted the driver
+		 * to use the new one yet.  Note - only the new queuecommand variant
+		 * passes a meaningful return value.
+		 */
+		if (host->hostt->use_new_eh_code) {
+			rtn = host->hostt->queuecommand(SCpnt, scsi_done);
+			if (rtn != 0) {
+				scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
+			}
+		} else {
+			host->hostt->queuecommand(SCpnt, scsi_old_done);
+		}
+	} else {
+		int temp;
 
-    /* Assign a unique nonzero serial_number. */
-    if (++serial_number == 0) serial_number = 1;
-    SCpnt->serial_number = serial_number;
-
-    /*
-     * We will wait MIN_RESET_DELAY clock ticks after the last reset so
-     * we can avoid the drive not being ready.
-     */
-    timeout = host->last_reset + MIN_RESET_DELAY;
-
-    if (host->resetting && time_before(jiffies, timeout)) {
-	int ticks_remaining = timeout - jiffies;
-	/*
-	 * NOTE: This may be executed from within an interrupt
-	 * handler!  This is bad, but for now, it'll do.  The irq
-	 * level of the interrupt handler has been masked out by the
-	 * platform dependent interrupt handling code already, so the
-	 * sti() here will not cause another call to the SCSI host's
-	 * interrupt handler (assuming there is one irq-level per
-	 * host).
-	 */
-	spin_unlock_irq(&io_request_lock);
-	while (--ticks_remaining >= 0) mdelay(1+999/HZ);
-	host->resetting = 0;
-	spin_lock_irq(&io_request_lock);
-    }
-
-    if( host->hostt->use_new_eh_code )
-      {
-        scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
-      }
-    else
-      {
-        scsi_add_timer(SCpnt, SCpnt->timeout_per_command, 
-                            scsi_old_times_out);
-      }
-
-    /*
-     * We will use a queued command if possible, otherwise we will emulate the
-     * queuing and calling of completion function ourselves.
-     */
-    SCSI_LOG_MLQUEUE(3,printk("internal_cmnd (host = %d, channel = %d, target = %d, "
-	   "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
-	   SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
-	   SCpnt->buffer, SCpnt->bufflen, SCpnt->done));
-
-    SCpnt->state = SCSI_STATE_QUEUED;
-    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-    if (host->can_queue)
-    {
-	SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n",
-                                  host->hostt->queuecommand));
-        /*
-         * Use the old error handling code if we haven't converted the driver
-         * to use the new one yet.  Note - only the new queuecommand variant
-         * passes a meaningful return value.
-         */
-        if( host->hostt->use_new_eh_code )
-          {
-            rtn = host->hostt->queuecommand (SCpnt, scsi_done);
-            if( rtn != 0 )
-            {
-                scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
-            }
-          }
-        else
-          {
-            host->hostt->queuecommand (SCpnt, scsi_old_done);
-          }
-    }
-    else
-    {
-	int temp;
-
-	SCSI_LOG_MLQUEUE(3,printk("command() :  routine at %p\n", host->hostt->command));
-	temp = host->hostt->command (SCpnt);
-	SCpnt->result = temp;
+		SCSI_LOG_MLQUEUE(3, printk("command() :  routine at %p\n", host->hostt->command));
+		temp = host->hostt->command(SCpnt);
+		SCpnt->result = temp;
 #ifdef DEBUG_DELAY
-	clock = jiffies + 4 * HZ;
-	spin_unlock_irq(&io_request_lock);
-	while (time_before(jiffies, clock)) barrier();
-	spin_lock_irq(&io_request_lock);
-	printk("done(host = %d, result = %04x) : routine at %p\n",
-	       host->host_no, temp, host->hostt->command);
-#endif
-        if( host->hostt->use_new_eh_code )
-          {
-            scsi_done(SCpnt);
-          }
-        else
-          {
-            scsi_old_done(SCpnt);
-          }
-    }
-    SCSI_LOG_MLQUEUE(3,printk("leaving internal_cmnd()\n"));
-    return rtn;
+		clock = jiffies + 4 * HZ;
+		spin_unlock_irq(&io_request_lock);
+		while (time_before(jiffies, clock))
+			barrier();
+		spin_lock_irq(&io_request_lock);
+		printk("done(host = %d, result = %04x) : routine at %p\n",
+		       host->host_no, temp, host->hostt->command);
+#endif
+		if (host->hostt->use_new_eh_code) {
+			scsi_done(SCpnt);
+		} else {
+			scsi_old_done(SCpnt);
+		}
+	}
+	SCSI_LOG_MLQUEUE(3, printk("leaving internal_cmnd()\n"));
+	return rtn;
 }
 
 /*
@@ -1466,95 +1457,93 @@
  * drivers go for the same host at the same time.
  */
 
-void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
-		  void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
-		  int timeout, int retries)
-{
-    struct Scsi_Host * host = SCpnt->host;
-    Scsi_Device      * device = SCpnt->device;
+void scsi_do_cmd(Scsi_Cmnd * SCpnt, const void *cmnd,
+	      void *buffer, unsigned bufflen, void (*done) (Scsi_Cmnd *),
+		 int timeout, int retries)
+{
+	struct Scsi_Host *host = SCpnt->host;
+	Scsi_Device *device = SCpnt->device;
+
+	SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+
+	SCSI_LOG_MLQUEUE(4,
+			 {
+			 int i;
+			 int target = SCpnt->target;
+			 printk("scsi_do_cmd (host = %d, channel = %d target = %d, "
+		    "buffer =%p, bufflen = %d, done = %p, timeout = %d, "
+				"retries = %d)\n"
+				"command : ", host->host_no, SCpnt->channel, target, buffer,
+				bufflen, done, timeout, retries);
+			 for (i = 0; i < 10; ++i)
+			 printk("%02x  ", ((unsigned char *) cmnd)[i]);
+			 printk("\n");
+			 });
+
+	if (!host) {
+		panic("Invalid or not present host.\n");
+	}
+	/*
+	 * We must prevent reentrancy to the lowlevel host driver.  This prevents
+	 * it - we enter a loop until the host we want to talk to is not busy.
+	 * Race conditions are prevented, as interrupts are disabled in between the
+	 * time we check for the host being not busy, and the time we mark it busy
+	 * ourselves.
+	 */
 
-    SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+	SCpnt->pid = scsi_pid++;
 
-SCSI_LOG_MLQUEUE(4,
-    {
-	int i;
-	int target = SCpnt->target;
-	printk ("scsi_do_cmd (host = %d, channel = %d target = %d, "
-		"buffer =%p, bufflen = %d, done = %p, timeout = %d, "
-		"retries = %d)\n"
-		"command : " , host->host_no, SCpnt->channel, target, buffer,
-		bufflen, done, timeout, retries);
-	for (i = 0; i < 10; ++i)
-	    printk ("%02x  ", ((unsigned char *) cmnd)[i]);
-	printk("\n");
-    });
+	while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
+		spin_unlock(&io_request_lock);	/* FIXME!!! */
+		SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
+		spin_lock_irq(&io_request_lock);	/* FIXME!!! */
+	}
+
+	if (host->block)
+		host_active = host;
+
+	host->host_busy++;
+	device->device_busy++;
 
-    if (!host)
-    {
-	panic ("Invalid or not present host.\n");
-    }
-
-
-    /*
-     * We must prevent reentrancy to the lowlevel host driver.  This prevents
-     * it - we enter a loop until the host we want to talk to is not busy.
-     * Race conditions are prevented, as interrupts are disabled in between the
-     * time we check for the host being not busy, and the time we mark it busy
-     * ourselves.
-     */
-
-    SCpnt->pid = scsi_pid++;
-
-    while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
-    	spin_unlock(&io_request_lock);	/* FIXME!!! */
-	SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
-    	spin_lock_irq(&io_request_lock);	/* FIXME!!! */
-    }
-
-    if (host->block) host_active = host;
-
-    host->host_busy++;
-    device->device_busy++;
-
-    /*
-     * Our own function scsi_done (which marks the host as not busy, disables
-     * the timeout counter, etc) will be called by us or by the
-     * scsi_hosts[host].queuecommand() function needs to also call
-     * the completion function for the high level driver.
-     */
-
-    memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12);
-    SCpnt->reset_chain = NULL;
-    SCpnt->serial_number = 0;
-    SCpnt->serial_number_at_timeout = 0;
-    SCpnt->bufflen = bufflen;
-    SCpnt->buffer = buffer;
-    SCpnt->flags = 0;
-    SCpnt->retries = 0;
-    SCpnt->allowed = retries;
-    SCpnt->done = done;
-    SCpnt->timeout_per_command = timeout;
-
-    memcpy ((void *) SCpnt->cmnd , (const void *) cmnd, 12);
-    /* Zero the sense buffer.  Some host adapters automatically request
-     * sense on error.  0 is not a valid sense code.
-     */
-    memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
-    SCpnt->request_buffer = buffer;
-    SCpnt->request_bufflen = bufflen;
-    SCpnt->old_use_sg = SCpnt->use_sg;
-    if (SCpnt->cmd_len == 0)
-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-    SCpnt->old_cmd_len = SCpnt->cmd_len;
-
-    /* Start the timer ticking.  */
-
-    SCpnt->internal_timeout = NORMAL_TIMEOUT;
-    SCpnt->abort_reason = 0;
-    SCpnt->result = 0;
-    internal_cmnd (SCpnt);
+	/*
+	 * Our own function scsi_done (which marks the host as not busy, disables
+	 * the timeout counter, etc) will be called by us or by the
+	 * scsi_hosts[host].queuecommand() function needs to also call
+	 * the completion function for the high level driver.
+	 */
+
+	memcpy((void *) SCpnt->data_cmnd, (const void *) cmnd, 12);
+	SCpnt->reset_chain = NULL;
+	SCpnt->serial_number = 0;
+	SCpnt->serial_number_at_timeout = 0;
+	SCpnt->bufflen = bufflen;
+	SCpnt->buffer = buffer;
+	SCpnt->flags = 0;
+	SCpnt->retries = 0;
+	SCpnt->allowed = retries;
+	SCpnt->done = done;
+	SCpnt->timeout_per_command = timeout;
+
+	memcpy((void *) SCpnt->cmnd, (const void *) cmnd, 12);
+	/* Zero the sense buffer.  Some host adapters automatically request
+	 * sense on error.  0 is not a valid sense code.
+	 */
+	memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+	SCpnt->request_buffer = buffer;
+	SCpnt->request_bufflen = bufflen;
+	SCpnt->old_use_sg = SCpnt->use_sg;
+	if (SCpnt->cmd_len == 0)
+		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->old_cmd_len = SCpnt->cmd_len;
+
+	/* Start the timer ticking.  */
+
+	SCpnt->internal_timeout = NORMAL_TIMEOUT;
+	SCpnt->abort_reason = 0;
+	SCpnt->result = 0;
+	internal_cmnd(SCpnt);
 
-    SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n"));
+	SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_do_cmd()\n"));
 }
 
 /* This function is the mid-level interrupt routine, which decides how
@@ -1577,60 +1566,57 @@
  * engineer something to deal with it so that only the outer layer ever does any real
  * processing.
  */
-void
-scsi_done (Scsi_Cmnd * SCpnt)
+void scsi_done(Scsi_Cmnd * SCpnt)
 {
 
-  /*
-   * We don't have to worry about this one timing out any more.
-   */
-  scsi_delete_timer(SCpnt);
-
-  /* Set the serial numbers back to zero */
-  SCpnt->serial_number = 0;
-
-  /*
-   * First, see whether this command already timed out.  If so, we ignore
-   * the response.  We treat it as if the command never finished.
-   *
-   * Since serial_number is now 0, the error handler cound detect this
-   * situation and avoid to call the the low level driver abort routine.
-   * (DB)
-   */
-  if( SCpnt->state == SCSI_STATE_TIMEOUT )
-    {
-      SCSI_LOG_MLCOMPLETE(1,printk("Ignoring completion of %p due to timeout status", SCpnt));
-      return;
-    }
-
-  SCpnt->serial_number_at_timeout = 0;
-  SCpnt->state = SCSI_STATE_BHQUEUE;
-  SCpnt->owner = SCSI_OWNER_BH_HANDLER;
-  SCpnt->bh_next = NULL;
-
-  /*
-   * Next, put this command in the BH queue.
-   * 
-   * We need a spinlock here, or compare and exchange if we can reorder incoming
-   * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times
-   * before bh is serviced. -jj
-   *
-   * We already have the io_request_lock here, since we are called from the
-   * interrupt handler or the error handler. (DB)
-   *
-   */
-  if (!scsi_bh_queue_head) {
-  	scsi_bh_queue_head = SCpnt;
-  	scsi_bh_queue_tail = SCpnt;
-  } else {
-  	scsi_bh_queue_tail->bh_next = SCpnt;
-  	scsi_bh_queue_tail = SCpnt;
-  }
-
-  /*
-   * Mark the bottom half handler to be run.
-   */
-  mark_bh(SCSI_BH);
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 */
+	scsi_delete_timer(SCpnt);
+
+	/* Set the serial numbers back to zero */
+	SCpnt->serial_number = 0;
+
+	/*
+	 * First, see whether this command already timed out.  If so, we ignore
+	 * the response.  We treat it as if the command never finished.
+	 *
+	 * Since serial_number is now 0, the error handler cound detect this
+	 * situation and avoid to call the the low level driver abort routine.
+	 * (DB)
+	 */
+	if (SCpnt->state == SCSI_STATE_TIMEOUT) {
+		SCSI_LOG_MLCOMPLETE(1, printk("Ignoring completion of %p due to timeout status", SCpnt));
+		return;
+	}
+	SCpnt->serial_number_at_timeout = 0;
+	SCpnt->state = SCSI_STATE_BHQUEUE;
+	SCpnt->owner = SCSI_OWNER_BH_HANDLER;
+	SCpnt->bh_next = NULL;
+
+	/*
+	 * Next, put this command in the BH queue.
+	 * 
+	 * We need a spinlock here, or compare and exchange if we can reorder incoming
+	 * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times
+	 * before bh is serviced. -jj
+	 *
+	 * We already have the io_request_lock here, since we are called from the
+	 * interrupt handler or the error handler. (DB)
+	 *
+	 */
+	if (!scsi_bh_queue_head) {
+		scsi_bh_queue_head = SCpnt;
+		scsi_bh_queue_tail = SCpnt;
+	} else {
+		scsi_bh_queue_tail->bh_next = SCpnt;
+		scsi_bh_queue_tail = SCpnt;
+	}
+
+	/*
+	 * Mark the bottom half handler to be run.
+	 */
+	mark_bh(SCSI_BH);
 }
 
 /*
@@ -1651,113 +1637,102 @@
  */
 void scsi_bottom_half_handler(void)
 {
-  Scsi_Cmnd        * SCpnt;
-  Scsi_Cmnd        * SCnext;
-  unsigned long      flags;
-  
-  spin_lock_irqsave(&io_request_lock, flags);
-
-  while(1==1)
-  {
-      SCpnt = scsi_bh_queue_head;
-      scsi_bh_queue_head = NULL;
-      
-      if( SCpnt == NULL ) {
-          spin_unlock_irqrestore(&io_request_lock, flags);
-          return;
-          }
-      
-      SCnext = SCpnt->bh_next;
-      
-      for(; SCpnt; SCpnt = SCnext)
-      {
-          SCnext = SCpnt->bh_next;
-          
-          switch( scsi_decide_disposition(SCpnt) )
-          {
-          case SUCCESS:
-              /*
-               * Add to BH queue.
-               */
-              SCSI_LOG_MLCOMPLETE(3,printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy,
-                     SCpnt->host->host_failed,
-                     SCpnt->result));
-              
-              scsi_finish_command(SCpnt);
-              break;
-          case NEEDS_RETRY:
-              /*
-               * We only come in here if we want to retry a command.  The
-               * test to see whether the command should be retried should be
-               * keeping track of the number of tries, so we don't end up looping,
-               * of course.
-               */
-              SCSI_LOG_MLCOMPLETE(3,printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy,
-                     SCpnt->host->host_failed, SCpnt->result));
-              
-              scsi_retry_command(SCpnt);
-              break;
-          case ADD_TO_MLQUEUE:
-              /* 
-               * This typically happens for a QUEUE_FULL message -
-               * typically only when the queue depth is only
-               * approximate for a given device.  Adding a command
-               * to the queue for the device will prevent further commands
-               * from being sent to the device, so we shouldn't end up
-               * with tons of things being sent down that shouldn't be.
-               */
-              scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY);
-              break;
-          default:
-              /*
-               * Here we have a fatal error of some sort.  Turn it over to
-               * the error handler.
-               */
-              SCSI_LOG_MLCOMPLETE(3,printk("Command failed %p %x active=%d busy=%d failed=%d\n", 
-                                           SCpnt, SCpnt->result,
-                                           atomic_read(&SCpnt->host->host_active),
-                                           SCpnt->host->host_busy,
-                                           SCpnt->host->host_failed));
-              
-              /*
-               * Dump the sense information too.
-               */
-              if ((status_byte (SCpnt->result) & CHECK_CONDITION) != 0)
-              {
-                  SCSI_LOG_MLCOMPLETE(3,print_sense("bh",SCpnt));
-              }
-
-
-              if( SCpnt->host->eh_wait != NULL )
-              {
-                  SCpnt->host->host_failed++;
-                  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-                  SCpnt->state = SCSI_STATE_FAILED;
-                  SCpnt->host->in_recovery = 1;
-                  /*
-                   * If the host is having troubles, then look to see if this was the last
-                   * command that might have failed.  If so, wake up the error handler.
-                   */
-                  if( SCpnt->host->host_busy == SCpnt->host->host_failed )
-                  {
-                    SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
-                                                      atomic_read(&SCpnt->host->eh_wait->count)));
-                      up(SCpnt->host->eh_wait);
-                  }
-              }
-              else
-              {
-                  /*
-                   * We only get here if the error recovery thread has died.
-                   */
-                  scsi_finish_command(SCpnt);
-              }
-          }
-      } /* for(; SCpnt...) */
+	Scsi_Cmnd *SCpnt;
+	Scsi_Cmnd *SCnext;
+	unsigned long flags;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	while (1 == 1) {
+		SCpnt = scsi_bh_queue_head;
+		scsi_bh_queue_head = NULL;
+
+		if (SCpnt == NULL) {
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			return;
+		}
+		SCnext = SCpnt->bh_next;
+
+		for (; SCpnt; SCpnt = SCnext) {
+			SCnext = SCpnt->bh_next;
 
-  } /* while(1==1) */
+			switch (scsi_decide_disposition(SCpnt)) {
+			case SUCCESS:
+				/*
+				 * Add to BH queue.
+				 */
+				SCSI_LOG_MLCOMPLETE(3, printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy,
+						SCpnt->host->host_failed,
+							 SCpnt->result));
+
+				scsi_finish_command(SCpnt);
+				break;
+			case NEEDS_RETRY:
+				/*
+				 * We only come in here if we want to retry a command.  The
+				 * test to see whether the command should be retried should be
+				 * keeping track of the number of tries, so we don't end up looping,
+				 * of course.
+				 */
+				SCSI_LOG_MLCOMPLETE(3, printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy,
+				SCpnt->host->host_failed, SCpnt->result));
+
+				scsi_retry_command(SCpnt);
+				break;
+			case ADD_TO_MLQUEUE:
+				/* 
+				 * This typically happens for a QUEUE_FULL message -
+				 * typically only when the queue depth is only
+				 * approximate for a given device.  Adding a command
+				 * to the queue for the device will prevent further commands
+				 * from being sent to the device, so we shouldn't end up
+				 * with tons of things being sent down that shouldn't be.
+				 */
+				scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY);
+				break;
+			default:
+				/*
+				 * Here we have a fatal error of some sort.  Turn it over to
+				 * the error handler.
+				 */
+				SCSI_LOG_MLCOMPLETE(3, printk("Command failed %p %x active=%d busy=%d failed=%d\n",
+						    SCpnt, SCpnt->result,
+				  atomic_read(&SCpnt->host->host_active),
+						  SCpnt->host->host_busy,
+					      SCpnt->host->host_failed));
+
+				/*
+				 * Dump the sense information too.
+				 */
+				if ((status_byte(SCpnt->result) & CHECK_CONDITION) != 0) {
+					SCSI_LOG_MLCOMPLETE(3, print_sense("bh", SCpnt));
+				}
+				if (SCpnt->host->eh_wait != NULL) {
+					SCpnt->host->host_failed++;
+					SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+					SCpnt->state = SCSI_STATE_FAILED;
+					SCpnt->host->in_recovery = 1;
+					/*
+					 * If the host is having troubles, then look to see if this was the last
+					 * command that might have failed.  If so, wake up the error handler.
+					 */
+					if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
+						SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
+										  atomic_read(&SCpnt->host->eh_wait->count)));
+						up(SCpnt->host->eh_wait);
+					}
+				} else {
+					/*
+					 * We only get here if the error recovery thread has died.
+					 */
+					scsi_finish_command(SCpnt);
+				}
+			}
+		}		/* for(; SCpnt...) */
+
+	}			/* while(1==1) */
 
-  spin_unlock_irqrestore(&io_request_lock, flags);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
 }
 
@@ -1771,18 +1746,17 @@
  *              level drivers should not become re-entrant as a result of
  *              this.
  */
-int
-scsi_retry_command(Scsi_Cmnd * SCpnt)
+int scsi_retry_command(Scsi_Cmnd * SCpnt)
 {
-  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
-          sizeof(SCpnt->data_cmnd));
-  SCpnt->request_buffer = SCpnt->buffer;
-  SCpnt->request_bufflen = SCpnt->bufflen;
-  SCpnt->use_sg = SCpnt->old_use_sg;
-  SCpnt->cmd_len = SCpnt->old_cmd_len;
-  SCpnt->result = 0;
-  memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
-  return internal_cmnd (SCpnt);
+	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+	       sizeof(SCpnt->data_cmnd));
+	SCpnt->request_buffer = SCpnt->buffer;
+	SCpnt->request_bufflen = SCpnt->bufflen;
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->cmd_len = SCpnt->old_cmd_len;
+	SCpnt->result = 0;
+	memset((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+	return internal_cmnd(SCpnt);
 }
 
 /*
@@ -1792,234 +1766,222 @@
  *              request, waking processes that are waiting on results,
  *              etc.
  */
-void
-scsi_finish_command(Scsi_Cmnd * SCpnt)
+void scsi_finish_command(Scsi_Cmnd * SCpnt)
 {
-    struct Scsi_Host * host;
-    Scsi_Device * device;
+	struct Scsi_Host *host;
+	Scsi_Device *device;
 
-    host = SCpnt->host;
-    device = SCpnt->device;
+	host = SCpnt->host;
+	device = SCpnt->device;
 
-    host->host_busy--; /* Indicate that we are free */
-    device->device_busy--; /* Decrement device usage counter. */
-  
-    if (host->block && host->host_busy == 0) 
-    {
-        host_active = NULL;
-        
-        /* For block devices "wake_up" is done in end_scsi_request */
-        if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) {
-            struct Scsi_Host * next;
-            
-            for (next = host->block; next != host; next = next->block)
-                wake_up(&next->host_wait);
-        }
-        
-    }
-  
-    /*
-     * Now try and drain the mid-level queue if any commands have been
-     * inserted.  Check to see whether the queue even has anything in
-     * it first, as otherwise this is useless overhead.
-     */
-    if( SCpnt->host->pending_commands != NULL )
-    {
-        scsi_mlqueue_finish(SCpnt->host, SCpnt->device);
-    }
-
-    wake_up(&host->host_wait);
-    
-    /*
-     * If we have valid sense information, then some kind of recovery
-     * must have taken place.  Make a note of this.
-     */
-    if( scsi_sense_valid(SCpnt) )
-    {
-        SCpnt->result |= (DRIVER_SENSE << 24);
-    }
-    
-    SCSI_LOG_MLCOMPLETE(3,printk("Notifying upper driver of completion for device %d %x\n",
-                                     SCpnt->device->id, SCpnt->result));
-    
-    SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
-    SCpnt->state = SCSI_STATE_FINISHED;
+	host->host_busy--;	/* Indicate that we are free */
+	device->device_busy--;	/* Decrement device usage counter. */
 
-    /* We can get here with use_sg=0, causing a panic in the upper level (DB) */
-    SCpnt->use_sg = SCpnt->old_use_sg;
+	if (host->block && host->host_busy == 0) {
+		host_active = NULL;
 
-    SCpnt->done (SCpnt);
-}
+		/* For block devices "wake_up" is done in end_scsi_request */
+		if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) {
+			struct Scsi_Host *next;
 
-#ifdef CONFIG_MODULES
-static int scsi_register_host(Scsi_Host_Template *);
-static void scsi_unregister_host(Scsi_Host_Template *);
-#endif
+			for (next = host->block; next != host; next = next->block)
+				wake_up(&next->host_wait);
+		}
+	}
+	/*
+	 * Now try and drain the mid-level queue if any commands have been
+	 * inserted.  Check to see whether the queue even has anything in
+	 * it first, as otherwise this is useless overhead.
+	 */
+	if (SCpnt->host->pending_commands != NULL) {
+		scsi_mlqueue_finish(SCpnt->host, SCpnt->device);
+	}
+	wake_up(&host->host_wait);
+
+	/*
+	 * If we have valid sense information, then some kind of recovery
+	 * must have taken place.  Make a note of this.
+	 */
+	if (scsi_sense_valid(SCpnt)) {
+		SCpnt->result |= (DRIVER_SENSE << 24);
+	}
+	SCSI_LOG_MLCOMPLETE(3, printk("Notifying upper driver of completion for device %d %x\n",
+				      SCpnt->device->id, SCpnt->result));
+
+	SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
+	SCpnt->state = SCSI_STATE_FINISHED;
+
+	/* We can get here with use_sg=0, causing a panic in the upper level (DB) */
+	SCpnt->use_sg = SCpnt->old_use_sg;
+
+	SCpnt->done(SCpnt);
+}
+
+#ifdef CONFIG_MODULES
+static int scsi_register_host(Scsi_Host_Template *);
+static void scsi_unregister_host(Scsi_Host_Template *);
+#endif
 
 void *scsi_malloc(unsigned int len)
 {
-    unsigned int nbits, mask;
-    int i, j;
-    if(len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
-	return NULL;
-
-    nbits = len >> 9;
-    mask = (1 << nbits) - 1;
-
-    for(i=0;i < dma_sectors / SECTORS_PER_PAGE; i++)
-	for(j=0; j<=SECTORS_PER_PAGE - nbits; j++){
-	    if ((dma_malloc_freelist[i] & (mask << j)) == 0){
-		dma_malloc_freelist[i] |= (mask << j);
-		scsi_dma_free_sectors -= nbits;
+	unsigned int nbits, mask;
+	int i, j;
+	if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
+		return NULL;
+
+	nbits = len >> 9;
+	mask = (1 << nbits) - 1;
+
+	for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
+		for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) {
+			if ((dma_malloc_freelist[i] & (mask << j)) == 0) {
+				dma_malloc_freelist[i] |= (mask << j);
+				scsi_dma_free_sectors -= nbits;
 #ifdef DEBUG
-                SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
-		printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9));
+				SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)));
+				printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9));
 #endif
-		return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
-	    }
-	}
-    return NULL;  /* Nope.  No more */
+				return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
+			}
+		}
+	return NULL;		/* Nope.  No more */
 }
 
 int scsi_free(void *obj, unsigned int len)
 {
-    unsigned int page, sector, nbits, mask;
+	unsigned int page, sector, nbits, mask;
 
 #ifdef DEBUG
-    unsigned long ret = 0;
+	unsigned long ret = 0;
 
 #ifdef __mips__
-    __asm__ __volatile__ ("move\t%0,$31":"=r"(ret));
+	__asm__ __volatile__("move\t%0,$31":"=r"(ret));
 #else
-   ret = __builtin_return_address(0);
+	ret = __builtin_return_address(0);
 #endif
-    printk("scsi_free %p %d\n",obj, len);
-    SCSI_LOG_MLQUEUE(3,printk("SFree: %p %d\n",obj, len));
+	printk("scsi_free %p %d\n", obj, len);
+	SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len));
 #endif
 
-    for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
-        unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
-        if ((unsigned long) obj >= page_addr &&
-	    (unsigned long) obj <  page_addr + PAGE_SIZE)
-	{
-	    sector = (((unsigned long) obj) - page_addr) >> 9;
+	for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
+		unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
+		if ((unsigned long) obj >= page_addr &&
+		    (unsigned long) obj < page_addr + PAGE_SIZE) {
+			sector = (((unsigned long) obj) - page_addr) >> 9;
 
-            nbits = len >> 9;
-            mask = (1 << nbits) - 1;
+			nbits = len >> 9;
+			mask = (1 << nbits) - 1;
 
-            if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
-                panic ("scsi_free:Bad memory alignment");
+			if ((mask << sector) >= (1 << SECTORS_PER_PAGE))
+				panic("scsi_free:Bad memory alignment");
 
-            if((dma_malloc_freelist[page] &
-                (mask << sector)) != (mask<<sector)){
+			if ((dma_malloc_freelist[page] &
+			     (mask << sector)) != (mask << sector)) {
 #ifdef DEBUG
-		printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
-                       obj, len, ret);
+				printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
+				       obj, len, ret);
 #endif
-                panic("scsi_free:Trying to free unused memory");
-            }
-            scsi_dma_free_sectors += nbits;
-            dma_malloc_freelist[page] &= ~(mask << sector);
-            return 0;
+				panic("scsi_free:Trying to free unused memory");
+			}
+			scsi_dma_free_sectors += nbits;
+			dma_malloc_freelist[page] &= ~(mask << sector);
+			return 0;
+		}
 	}
-    }
-    panic("scsi_free:Bad offset");
+	panic("scsi_free:Bad offset");
 }
 
 
-int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
+int scsi_loadable_module_flag;	/* Set after we scan builtin drivers */
 
-void * scsi_init_malloc(unsigned int size, int gfp_mask)
+void *scsi_init_malloc(unsigned int size, int gfp_mask)
 {
-    void * retval;
+	void *retval;
 
-    /*
-     * For buffers used by the DMA pool, we assume page aligned 
-     * structures.
-     */
-    if ((size % PAGE_SIZE) == 0) {
-	int order, a_size;
-	for (order = 0, a_size = PAGE_SIZE;
-             a_size < size; order++, a_size <<= 1)
-            ;
-	retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
-    } else
-	retval = kmalloc(size, gfp_mask);
+	/*
+	 * For buffers used by the DMA pool, we assume page aligned 
+	 * structures.
+	 */
+	if ((size % PAGE_SIZE) == 0) {
+		int order, a_size;
+		for (order = 0, a_size = PAGE_SIZE;
+		     a_size < size; order++, a_size <<= 1);
+		retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
+	} else
+		retval = kmalloc(size, gfp_mask);
 
-    if (retval)
-	memset(retval, 0, size);
-    return retval;
+	if (retval)
+		memset(retval, 0, size);
+	return retval;
 }
 
 
-void scsi_init_free(char * ptr, unsigned int size)
+void scsi_init_free(char *ptr, unsigned int size)
 {
-    /*
-     * We need this special code here because the DMA pool assumes
-     * page aligned data.  Besides, it is wasteful to allocate
-     * page sized chunks with kmalloc.
-     */
-    if ((size % PAGE_SIZE) == 0) {
-    	int order, a_size;
+	/*
+	 * We need this special code here because the DMA pool assumes
+	 * page aligned data.  Besides, it is wasteful to allocate
+	 * page sized chunks with kmalloc.
+	 */
+	if ((size % PAGE_SIZE) == 0) {
+		int order, a_size;
 
-	for (order = 0, a_size = PAGE_SIZE;
-	     a_size < size; order++, a_size <<= 1)
-	    ;
-	free_pages((unsigned long)ptr, order);
-    } else
-	kfree(ptr);
+		for (order = 0, a_size = PAGE_SIZE;
+		     a_size < size; order++, a_size <<= 1);
+		free_pages((unsigned long) ptr, order);
+	} else
+		kfree(ptr);
 }
 
 void scsi_build_commandblocks(Scsi_Device * SDpnt)
 {
-    struct Scsi_Host *host = SDpnt->host;
-    int j;
-    Scsi_Cmnd * SCpnt;
-
-    if (SDpnt->queue_depth == 0)
-        SDpnt->queue_depth = host->cmd_per_lun;
-    SDpnt->device_queue = NULL;
-
-    for(j=0;j<SDpnt->queue_depth;j++){
-        SCpnt = (Scsi_Cmnd *)
-              scsi_init_malloc(sizeof(Scsi_Cmnd),
-                               GFP_ATOMIC |
-                               (host->unchecked_isa_dma ? GFP_DMA : 0));
-	if (NULL == SCpnt)
-	    break; /* If not, the next line will oops ... */
-        memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
-	SCpnt->host                      = host;
-	SCpnt->device                    = SDpnt;
-	SCpnt->target                    = SDpnt->id;
-	SCpnt->lun                       = SDpnt->lun;
-	SCpnt->channel                   = SDpnt->channel;
-	SCpnt->request.rq_status         = RQ_INACTIVE;
-        SCpnt->host_wait                 = FALSE;
-        SCpnt->device_wait               = FALSE;
-	SCpnt->use_sg                    = 0;
-	SCpnt->old_use_sg                = 0;
-	SCpnt->old_cmd_len               = 0;
-	SCpnt->underflow                 = 0;
-	SCpnt->transfersize              = 0;
-	SCpnt->serial_number             = 0;
-	SCpnt->serial_number_at_timeout  = 0;
-	SCpnt->host_scribble             = NULL;
-	SCpnt->next                      = SDpnt->device_queue;
-	SDpnt->device_queue              = SCpnt;
-        SCpnt->state                     = SCSI_STATE_UNUSED;
-        SCpnt->owner                     = SCSI_OWNER_NOBODY;
-    }
-    if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */
-	printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n",
-	       SDpnt->queue_depth, j);
-	SDpnt->queue_depth = j;
-	SDpnt->has_cmdblocks = (0 != j);
-    }
-    else
-	SDpnt->has_cmdblocks = 1;
+	struct Scsi_Host *host = SDpnt->host;
+	int j;
+	Scsi_Cmnd *SCpnt;
+
+	if (SDpnt->queue_depth == 0)
+		SDpnt->queue_depth = host->cmd_per_lun;
+	SDpnt->device_queue = NULL;
+
+	for (j = 0; j < SDpnt->queue_depth; j++) {
+		SCpnt = (Scsi_Cmnd *)
+		    scsi_init_malloc(sizeof(Scsi_Cmnd),
+				     GFP_ATOMIC |
+				(host->unchecked_isa_dma ? GFP_DMA : 0));
+		if (NULL == SCpnt)
+			break;	/* If not, the next line will oops ... */
+		memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
+		SCpnt->host = host;
+		SCpnt->device = SDpnt;
+		SCpnt->target = SDpnt->id;
+		SCpnt->lun = SDpnt->lun;
+		SCpnt->channel = SDpnt->channel;
+		SCpnt->request.rq_status = RQ_INACTIVE;
+		SCpnt->host_wait = FALSE;
+		SCpnt->device_wait = FALSE;
+		SCpnt->use_sg = 0;
+		SCpnt->old_use_sg = 0;
+		SCpnt->old_cmd_len = 0;
+		SCpnt->underflow = 0;
+		SCpnt->transfersize = 0;
+		SCpnt->serial_number = 0;
+		SCpnt->serial_number_at_timeout = 0;
+		SCpnt->host_scribble = NULL;
+		SCpnt->next = SDpnt->device_queue;
+		SDpnt->device_queue = SCpnt;
+		SCpnt->state = SCSI_STATE_UNUSED;
+		SCpnt->owner = SCSI_OWNER_NOBODY;
+	}
+	if (j < SDpnt->queue_depth) {	/* low on space (D.Gilbert 990424) */
+		printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n",
+		       SDpnt->queue_depth, j);
+		SDpnt->queue_depth = j;
+		SDpnt->has_cmdblocks = (0 != j);
+	} else
+		SDpnt->has_cmdblocks = 1;
 }
 
-#ifndef MODULE /* { */
+#ifndef MODULE			/* { */
 /*
  * scsi_dev_init() is our initialization routine, which in turn calls host
  * initialization, bus scanning, and sd/st initialization routines.
@@ -2027,449 +1989,398 @@
  */
 int __init scsi_dev_init(void)
 {
-    Scsi_Device * SDpnt;
-    struct Scsi_Host * shpnt;
-    struct Scsi_Device_Template * sdtpnt;
+	Scsi_Device *SDpnt;
+	struct Scsi_Host *shpnt;
+	struct Scsi_Device_Template *sdtpnt;
 #ifdef FOO_ON_YOU
-    return;
+	return;
 #endif
 
-    /* Yes we're here... */
+	/* Yes we're here... */
 #if CONFIG_PROC_FS
-    dispatch_scsi_info_ptr = dispatch_scsi_info;
+	dispatch_scsi_info_ptr = dispatch_scsi_info;
 #endif
 
-    /* Init a few things so we can "malloc" memory. */
-    scsi_loadable_module_flag = 0;
+	/* Init a few things so we can "malloc" memory. */
+	scsi_loadable_module_flag = 0;
 
-    /* Register the /proc/scsi/scsi entry */
+	/* Register the /proc/scsi/scsi entry */
 #if CONFIG_PROC_FS
-    proc_scsi_register(0, &proc_scsi_scsi);
+	proc_scsi_register(0, &proc_scsi_scsi);
 #endif
 
-    /* initialize all hosts */
-    scsi_init();
+	/* initialize all hosts */
+	scsi_init();
 
-    /*
-     * This is where the processing takes place for most everything
-     * when commands are completed.  Until we do this, we will not be able
-     * to queue any commands.
-     */
-    init_bh(SCSI_BH, scsi_bottom_half_handler);
-
-    for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-	scan_scsis(shpnt,0,0,0,0);           /* scan for scsi devices */
-	if (shpnt->select_queue_depths != NULL)
-	    (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
-    }
-
-    printk("scsi : detected ");
-    for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-	if (sdtpnt->dev_noticed && sdtpnt->name)
-	    printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
-		   (sdtpnt->dev_noticed != 1) ? "s" : "");
-    printk("total.\n");
-
-    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-	if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) 
-        {
-            /* SDpnt->scsi_request_fn = NULL; */
-            for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-                if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-            if(SDpnt->attached) {
-		scsi_build_commandblocks(SDpnt);
-		if (0 == SDpnt->has_cmdblocks) {
-		    printk("scsi_dev_init: DANGER, no command blocks\n");
-		    /* What to do now ?? */
-		}
-	    }
-        }
-    }
-    
-    /*
-     * This should build the DMA pool.
-     */
-    resize_dma_pool();
-
-    /*
-     * OK, now we finish the initialization by doing spin-up, read
-     * capacity, etc, etc
-     */
-    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-	if(sdtpnt->finish && sdtpnt->nr_dev)
-	    (*sdtpnt->finish)();
+	/*
+	 * This is where the processing takes place for most everything
+	 * when commands are completed.  Until we do this, we will not be able
+	 * to queue any commands.
+	 */
+	init_bh(SCSI_BH, scsi_bottom_half_handler);
 
-    scsi_loadable_module_flag = 1;
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		scan_scsis(shpnt, 0, 0, 0, 0);	/* scan for scsi devices */
+		if (shpnt->select_queue_depths != NULL)
+			(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
+	}
+
+	printk("scsi : detected ");
+	for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+		if (sdtpnt->dev_noticed && sdtpnt->name)
+			printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
+			       (sdtpnt->dev_noticed != 1) ? "s" : "");
+	printk("total.\n");
+
+	for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+		if (sdtpnt->init && sdtpnt->dev_noticed)
+			(*sdtpnt->init) ();
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
+			/* SDpnt->scsi_request_fn = NULL; */
+			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+				if (sdtpnt->attach)
+					(*sdtpnt->attach) (SDpnt);
+			if (SDpnt->attached) {
+				scsi_build_commandblocks(SDpnt);
+				if (0 == SDpnt->has_cmdblocks) {
+					printk("scsi_dev_init: DANGER, no command blocks\n");
+					/* What to do now ?? */
+				}
+			}
+		}
+	}
 
-    return 0;
+	/*
+	 * This should build the DMA pool.
+	 */
+	resize_dma_pool();
+
+	/*
+	 * OK, now we finish the initialization by doing spin-up, read
+	 * capacity, etc, etc
+	 */
+	for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+		if (sdtpnt->finish && sdtpnt->nr_dev)
+			(*sdtpnt->finish) ();
+
+	scsi_loadable_module_flag = 1;
+
+	return 0;
 }
-#endif /* MODULE */   /* } */
+#endif	/* MODULE */		/* } */
 
 static void print_inquiry(unsigned char *data)
 {
-    int i;
+	int i;
 
-    printk("  Vendor: ");
-    for (i = 8; i < 16; i++)
-    {
-	if (data[i] >= 0x20 && i < data[4] + 5)
-	    printk("%c", data[i]);
-	else
-	    printk(" ");
-    }
+	printk("  Vendor: ");
+	for (i = 8; i < 16; i++) {
+		if (data[i] >= 0x20 && i < data[4] + 5)
+			printk("%c", data[i]);
+		else
+			printk(" ");
+	}
 
-    printk("  Model: ");
-    for (i = 16; i < 32; i++)
-    {
-	if (data[i] >= 0x20 && i < data[4] + 5)
-	    printk("%c", data[i]);
-	else
-	    printk(" ");
-    }
+	printk("  Model: ");
+	for (i = 16; i < 32; i++) {
+		if (data[i] >= 0x20 && i < data[4] + 5)
+			printk("%c", data[i]);
+		else
+			printk(" ");
+	}
 
-    printk("  Rev: ");
-    for (i = 32; i < 36; i++)
-    {
-	if (data[i] >= 0x20 && i < data[4] + 5)
-	    printk("%c", data[i]);
-	else
-	    printk(" ");
-    }
+	printk("  Rev: ");
+	for (i = 32; i < 36; i++) {
+		if (data[i] >= 0x20 && i < data[4] + 5)
+			printk("%c", data[i]);
+		else
+			printk(" ");
+	}
 
-    printk("\n");
+	printk("\n");
 
-    i = data[0] & 0x1f;
+	i = data[0] & 0x1f;
 
-    printk("  Type:   %s ",
-	   i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          " );
-    printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
-    if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
-	printk(" CCS\n");
-    else
-	printk("\n");
+	printk("  Type:   %s ",
+	       i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown          ");
+	printk("                 ANSI SCSI revision: %02x", data[2] & 0x07);
+	if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
+		printk(" CCS\n");
+	else
+		printk("\n");
 }
 
 
 #ifdef CONFIG_PROC_FS
 int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
-		    int hostno, int inout)
+		   int hostno, int inout)
 {
-    Scsi_Cmnd *SCpnt;
-    struct Scsi_Device_Template *SDTpnt;
-    Scsi_Device *scd;
-    struct Scsi_Host *HBA_ptr;
-    char *p;
-    int   host, channel, id, lun;
-    int	  size, len = 0;
-    off_t begin = 0;
-    off_t pos = 0;
-
-    if(inout == 0) {
-        /*
-         * First, see if there are any attached devices or not.
-         */
-	for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
-        {
-            if( HBA_ptr->host_queue != NULL )
-            {
-                break;
-            }
-        }
-	size = sprintf(buffer+len,"Attached devices: %s\n", (HBA_ptr)?"":"none");
-	len += size;
-	pos = begin + len;
-	for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
-        {
+	Scsi_Cmnd *SCpnt;
+	struct Scsi_Device_Template *SDTpnt;
+	Scsi_Device *scd;
+	struct Scsi_Host *HBA_ptr;
+	char *p;
+	int host, channel, id, lun;
+	int size, len = 0;
+	off_t begin = 0;
+	off_t pos = 0;
+
+	if (inout == 0) {
+		/*
+		 * First, see if there are any attached devices or not.
+		 */
+		for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
+			if (HBA_ptr->host_queue != NULL) {
+				break;
+			}
+		}
+		size = sprintf(buffer + len, "Attached devices: %s\n", (HBA_ptr) ? "" : "none");
+		len += size;
+		pos = begin + len;
+		for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
 #if 0
-	    size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
-	                    HBA_ptr->hostt->procname);
-	    len += size;
-	    pos = begin + len;
-#endif
-	    for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
-            {
-                proc_print_scsidevice(scd, buffer, &size, len);
-                len += size;
-                pos = begin + len;
-                
-                if (pos < offset) {
-                    len = 0;
-                    begin = pos;
-                }
-                if (pos > offset + length)
-                    goto stop_output;
-	    }
-	}
-
-    stop_output:
-	*start=buffer+(offset-begin);   /* Start of wanted data */
-	len-=(offset-begin);	        /* Start slop */
-	if(len>length)
-	    len = length;		/* Ending slop */
-	return (len);
-    }
-
-    if(!buffer || length < 11 || strncmp("scsi", buffer, 4))
-	return(-EINVAL);
-
-    /*
-     * Usage: echo "scsi dump #N" > /proc/scsi/scsi
-     * to dump status of all scsi commands.  The number is used to specify the level
-     * of detail in the dump.
-     */
-    if(!strncmp("dump", buffer + 5, 4)) 
-    {
-        unsigned int level;
-
-	p = buffer + 10;
-
-        if( *p == '\0' )
-            return (-EINVAL);
-
-        level = simple_strtoul(p, NULL, 0);
-        scsi_dump_status(level);
-    }
-    /*
-     * Usage: echo "scsi log token #N" > /proc/scsi/scsi
-     * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
-     * llcomplete,hlqueue,hlcomplete]
-     */
-#if CONFIG_SCSI_LOGGING /* { */
-
-    if(!strncmp("log", buffer + 5, 3)) 
-    {
-        char * token;
-        unsigned int level;
-
-	p = buffer + 9;
-        token = p;
-        while(*p != ' ' && *p != '\t' && *p != '\0')
-        {
-            p++;
-        }
-
-        if( *p == '\0' )
-        {
-            if( strncmp(token, "all", 3) == 0 )
-            {
-                /*
-                 * Turn on absolutely everything.
-                 */
-                scsi_logging_level = ~0;
-            }
-            else if( strncmp(token, "none", 4) == 0 )
-            {
-                /*
-                 * Turn off absolutely everything.
-                 */
-                scsi_logging_level = 0;
-            }
-            else
-            {
-                return (-EINVAL);
-            }
-        }
-        else
-        {
-            *p++ = '\0';
-            
-            level = simple_strtoul(p, NULL, 0);
-            
-            /*
-             * Now figure out what to do with it.
-             */
-            if( strcmp(token, "error") == 0 )
-            {
-                SCSI_SET_ERROR_RECOVERY_LOGGING(level);
-            }
-            else if( strcmp(token, "timeout") == 0 )
-            {
-                SCSI_SET_TIMEOUT_LOGGING(level);
-            }
-            else if( strcmp(token, "scan") == 0 )
-            {
-                SCSI_SET_SCAN_BUS_LOGGING(level);
-            }
-            else if( strcmp(token, "mlqueue") == 0 )
-            {
-                SCSI_SET_MLQUEUE_LOGGING(level);
-            }
-            else if( strcmp(token, "mlcomplete") == 0 )
-            {
-                SCSI_SET_MLCOMPLETE_LOGGING(level);
-            }
-            else if( strcmp(token, "llqueue") == 0 )
-            {
-                SCSI_SET_LLQUEUE_LOGGING(level);
-            }
-            else if( strcmp(token, "llcomplete") == 0 )
-            {
-                SCSI_SET_LLCOMPLETE_LOGGING(level);
-            }
-            else if( strcmp(token, "hlqueue") == 0 )
-            {
-                SCSI_SET_HLQUEUE_LOGGING(level);
-            }
-            else if( strcmp(token, "hlcomplete") == 0 )
-            {
-                SCSI_SET_HLCOMPLETE_LOGGING(level);
-            }
-            else if( strcmp(token, "ioctl") == 0 )
-            {
-                SCSI_SET_IOCTL_LOGGING(level);
-            }
-            else
-            {
-                return (-EINVAL);
-            }
-        }
-
-        printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level);
-    }
-#endif /* CONFIG_SCSI_LOGGING */ /* } */
-
-    /*
-     * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
-     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
-     * Consider this feature BETA.
-     *     CAUTION: This is not for hotplugging your peripherals. As
-     *     SCSI was not designed for this you could damage your
-     *     hardware !
-     * However perhaps it is legal to switch on an
-     * already connected device. It is perhaps not
-     * guaranteed this device doesn't corrupt an ongoing data transfer.
-     */
-    if(!strncmp("add-single-device", buffer + 5, 17)) {
-	p = buffer + 23;
-
-        host    = simple_strtoul(p, &p, 0);
-        channel = simple_strtoul(p+1, &p, 0);
-        id      = simple_strtoul(p+1, &p, 0);
-        lun     = simple_strtoul(p+1, &p, 0);
-
-	printk("scsi singledevice %d %d %d %d\n", host, channel,
-			id, lun);
-
-        for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
-        {
-            if( HBA_ptr->host_no == host )
-            {
-                break;
-            }
-        }
-	if(!HBA_ptr)
-	    return(-ENXIO);
-
-        for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
-        {
-            if((scd->channel == channel
-                && scd->id == id
-                && scd->lun == lun))
-            {
-                break;
-            }
-        }
-
-	if(scd)
-	    return(-ENOSYS);  /* We do not yet support unplugging */
-
-	scan_scsis (HBA_ptr, 1, channel, id, lun);
-
-        /* FIXME (DB) This assumes that the queue_depth routines can be used
-           in this context as well, while they were all designed to be
-           called only once after the detect routine. (DB) */
-	if (HBA_ptr->select_queue_depths != NULL)
-		(HBA_ptr->select_queue_depths)(HBA_ptr, HBA_ptr->host_queue);
-
-	return(length);
-
-    }
-
-    /*
-     * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
-     * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
-     *
-     * Consider this feature pre-BETA.
-     *
-     *     CAUTION: This is not for hotplugging your peripherals. As
-     *     SCSI was not designed for this you could damage your
-     *     hardware and thoroughly confuse the SCSI subsystem.
-     *
-     */
-    else if(!strncmp("remove-single-device", buffer + 5, 20)) {
-        p = buffer + 26;
-
-        host    = simple_strtoul(p, &p, 0);
-        channel = simple_strtoul(p+1, &p, 0);
-        id      = simple_strtoul(p+1, &p, 0);
-        lun     = simple_strtoul(p+1, &p, 0);
-
-
-        for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
-        {
-            if( HBA_ptr->host_no == host )
-            {
-                break;
-            }
-        }
-	if(!HBA_ptr)
-	    return(-ENODEV);
-
-        for(scd = HBA_ptr->host_queue; scd; scd = scd->next) 
-        {
-            if((scd->channel == channel
-                && scd->id == id
-                && scd->lun == lun))
-            {
-                break;
-            }
-        }
-
-        if(scd == NULL)
-            return(-ENODEV);  /* there is no such device attached */
-
-        if(scd->access_count)
-            return(-EBUSY);
-
-        SDTpnt = scsi_devicelist;
-        while(SDTpnt != NULL) {
-            if(SDTpnt->detach) (*SDTpnt->detach)(scd);
-            SDTpnt = SDTpnt->next;
-        }
-
-        if(scd->attached == 0) {
-            /*
-             * Nobody is using this device any more.
-             * Free all of the command structures.
-             */
-            for(SCpnt=scd->device_queue; SCpnt; SCpnt = SCpnt->next)
-            {
-                scd->device_queue = SCpnt->next;
-                scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
-            }
-            /* Now we can remove the device structure */
-            if( scd->next != NULL )
-                scd->next->prev = scd->prev;
-
-            if( scd->prev != NULL )
-                scd->prev->next = scd->next;
-
-            if( HBA_ptr->host_queue == scd )
-            {
-                HBA_ptr->host_queue = scd->next;
-            }
-
-            scsi_init_free((char *) scd, sizeof(Scsi_Device));
-        } else {
-            return(-EBUSY);
-        }
-        return(0);
-    }
-    return(-EINVAL);
+			size += sprintf(buffer + len, "scsi%2d: %s\n", (int) HBA_ptr->host_no,
+					HBA_ptr->hostt->procname);
+			len += size;
+			pos = begin + len;
+#endif
+			for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
+				proc_print_scsidevice(scd, buffer, &size, len);
+				len += size;
+				pos = begin + len;
+
+				if (pos < offset) {
+					len = 0;
+					begin = pos;
+				}
+				if (pos > offset + length)
+					goto stop_output;
+			}
+		}
+
+	stop_output:
+		*start = buffer + (offset - begin);	/* Start of wanted data */
+		len -= (offset - begin);	/* Start slop */
+		if (len > length)
+			len = length;	/* Ending slop */
+		return (len);
+	}
+	if (!buffer || length < 11 || strncmp("scsi", buffer, 4))
+		return (-EINVAL);
+
+	/*
+	 * Usage: echo "scsi dump #N" > /proc/scsi/scsi
+	 * to dump status of all scsi commands.  The number is used to specify the level
+	 * of detail in the dump.
+	 */
+	if (!strncmp("dump", buffer + 5, 4)) {
+		unsigned int level;
+
+		p = buffer + 10;
+
+		if (*p == '\0')
+			return (-EINVAL);
+
+		level = simple_strtoul(p, NULL, 0);
+		scsi_dump_status(level);
+	}
+	/*
+	 * Usage: echo "scsi log token #N" > /proc/scsi/scsi
+	 * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
+	 * llcomplete,hlqueue,hlcomplete]
+	 */
+#if CONFIG_SCSI_LOGGING		/* { */
+
+	if (!strncmp("log", buffer + 5, 3)) {
+		char *token;
+		unsigned int level;
+
+		p = buffer + 9;
+		token = p;
+		while (*p != ' ' && *p != '\t' && *p != '\0') {
+			p++;
+		}
+
+		if (*p == '\0') {
+			if (strncmp(token, "all", 3) == 0) {
+				/*
+				 * Turn on absolutely everything.
+				 */
+				scsi_logging_level = ~0;
+			} else if (strncmp(token, "none", 4) == 0) {
+				/*
+				 * Turn off absolutely everything.
+				 */
+				scsi_logging_level = 0;
+			} else {
+				return (-EINVAL);
+			}
+		} else {
+			*p++ = '\0';
+
+			level = simple_strtoul(p, NULL, 0);
+
+			/*
+			 * Now figure out what to do with it.
+			 */
+			if (strcmp(token, "error") == 0) {
+				SCSI_SET_ERROR_RECOVERY_LOGGING(level);
+			} else if (strcmp(token, "timeout") == 0) {
+				SCSI_SET_TIMEOUT_LOGGING(level);
+			} else if (strcmp(token, "scan") == 0) {
+				SCSI_SET_SCAN_BUS_LOGGING(level);
+			} else if (strcmp(token, "mlqueue") == 0) {
+				SCSI_SET_MLQUEUE_LOGGING(level);
+			} else if (strcmp(token, "mlcomplete") == 0) {
+				SCSI_SET_MLCOMPLETE_LOGGING(level);
+			} else if (strcmp(token, "llqueue") == 0) {
+				SCSI_SET_LLQUEUE_LOGGING(level);
+			} else if (strcmp(token, "llcomplete") == 0) {
+				SCSI_SET_LLCOMPLETE_LOGGING(level);
+			} else if (strcmp(token, "hlqueue") == 0) {
+				SCSI_SET_HLQUEUE_LOGGING(level);
+			} else if (strcmp(token, "hlcomplete") == 0) {
+				SCSI_SET_HLCOMPLETE_LOGGING(level);
+			} else if (strcmp(token, "ioctl") == 0) {
+				SCSI_SET_IOCTL_LOGGING(level);
+			} else {
+				return (-EINVAL);
+			}
+		}
+
+		printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level);
+	}
+#endif	/* CONFIG_SCSI_LOGGING */ /* } */
+
+	/*
+	 * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
+	 * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+	 * Consider this feature BETA.
+	 *     CAUTION: This is not for hotplugging your peripherals. As
+	 *     SCSI was not designed for this you could damage your
+	 *     hardware !
+	 * However perhaps it is legal to switch on an
+	 * already connected device. It is perhaps not
+	 * guaranteed this device doesn't corrupt an ongoing data transfer.
+	 */
+	if (!strncmp("add-single-device", buffer + 5, 17)) {
+		p = buffer + 23;
+
+		host = simple_strtoul(p, &p, 0);
+		channel = simple_strtoul(p + 1, &p, 0);
+		id = simple_strtoul(p + 1, &p, 0);
+		lun = simple_strtoul(p + 1, &p, 0);
+
+		printk("scsi singledevice %d %d %d %d\n", host, channel,
+		       id, lun);
+
+		for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
+			if (HBA_ptr->host_no == host) {
+				break;
+			}
+		}
+		if (!HBA_ptr)
+			return (-ENXIO);
+
+		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
+			if ((scd->channel == channel
+			     && scd->id == id
+			     && scd->lun == lun)) {
+				break;
+			}
+		}
+
+		if (scd)
+			return (-ENOSYS);	/* We do not yet support unplugging */
+
+		scan_scsis(HBA_ptr, 1, channel, id, lun);
+
+		/* FIXME (DB) This assumes that the queue_depth routines can be used
+		   in this context as well, while they were all designed to be
+		   called only once after the detect routine. (DB) */
+		if (HBA_ptr->select_queue_depths != NULL)
+			(HBA_ptr->select_queue_depths) (HBA_ptr, HBA_ptr->host_queue);
+
+		return (length);
+
+	}
+	/*
+	 * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
+	 * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+	 *
+	 * Consider this feature pre-BETA.
+	 *
+	 *     CAUTION: This is not for hotplugging your peripherals. As
+	 *     SCSI was not designed for this you could damage your
+	 *     hardware and thoroughly confuse the SCSI subsystem.
+	 *
+	 */
+	else if (!strncmp("remove-single-device", buffer + 5, 20)) {
+		p = buffer + 26;
+
+		host = simple_strtoul(p, &p, 0);
+		channel = simple_strtoul(p + 1, &p, 0);
+		id = simple_strtoul(p + 1, &p, 0);
+		lun = simple_strtoul(p + 1, &p, 0);
+
+
+		for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next) {
+			if (HBA_ptr->host_no == host) {
+				break;
+			}
+		}
+		if (!HBA_ptr)
+			return (-ENODEV);
+
+		for (scd = HBA_ptr->host_queue; scd; scd = scd->next) {
+			if ((scd->channel == channel
+			     && scd->id == id
+			     && scd->lun == lun)) {
+				break;
+			}
+		}
+
+		if (scd == NULL)
+			return (-ENODEV);	/* there is no such device attached */
+
+		if (scd->access_count)
+			return (-EBUSY);
+
+		SDTpnt = scsi_devicelist;
+		while (SDTpnt != NULL) {
+			if (SDTpnt->detach)
+				(*SDTpnt->detach) (scd);
+			SDTpnt = SDTpnt->next;
+		}
+
+		if (scd->attached == 0) {
+			/*
+			 * Nobody is using this device any more.
+			 * Free all of the command structures.
+			 */
+			for (SCpnt = scd->device_queue; SCpnt; SCpnt = SCpnt->next) {
+				scd->device_queue = SCpnt->next;
+				scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
+			}
+			/* Now we can remove the device structure */
+			if (scd->next != NULL)
+				scd->next->prev = scd->prev;
+
+			if (scd->prev != NULL)
+				scd->prev->next = scd->next;
+
+			if (HBA_ptr->host_queue == scd) {
+				HBA_ptr->host_queue = scd->next;
+			}
+			scsi_init_free((char *) scd, sizeof(Scsi_Device));
+		} else {
+			return (-EBUSY);
+		}
+		return (0);
+	}
+	return (-EINVAL);
 }
 #endif
 
@@ -2479,197 +2390,186 @@
  */
 static void resize_dma_pool(void)
 {
-    int i, k;
-    unsigned long size;
-    struct Scsi_Host * shpnt;
-    struct Scsi_Host * host = NULL;
-    Scsi_Device * SDpnt;
-    FreeSectorBitmap * new_dma_malloc_freelist = NULL;
-    unsigned int new_dma_sectors = 0;
-    unsigned int new_need_isa_buffer = 0;
-    unsigned char ** new_dma_malloc_pages = NULL;
-    int out_of_space = 0;
+	int i, k;
+	unsigned long size;
+	struct Scsi_Host *shpnt;
+	struct Scsi_Host *host = NULL;
+	Scsi_Device *SDpnt;
+	FreeSectorBitmap *new_dma_malloc_freelist = NULL;
+	unsigned int new_dma_sectors = 0;
+	unsigned int new_need_isa_buffer = 0;
+	unsigned char **new_dma_malloc_pages = NULL;
+	int out_of_space = 0;
+
+	if (!scsi_hostlist) {
+		/*
+		 * Free up the DMA pool.
+		 */
+		if (scsi_dma_free_sectors != dma_sectors)
+			panic("SCSI DMA pool memory leak %d %d\n", scsi_dma_free_sectors, dma_sectors);
 
-    if( !scsi_hostlist )
-    {
-	/*
-	 * Free up the DMA pool.
-	 */
-	if( scsi_dma_free_sectors != dma_sectors )
-	    panic("SCSI DMA pool memory leak %d %d\n",scsi_dma_free_sectors,dma_sectors);
+		for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
+			scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
+		if (dma_malloc_pages)
+			scsi_init_free((char *) dma_malloc_pages,
+				       (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
+		dma_malloc_pages = NULL;
+		if (dma_malloc_freelist)
+			scsi_init_free((char *) dma_malloc_freelist,
+				       (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_freelist));
+		dma_malloc_freelist = NULL;
+		dma_sectors = 0;
+		scsi_dma_free_sectors = 0;
+		return;
+	}
+	/* Next, check to see if we need to extend the DMA buffer pool */
 
-	for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++)
-	    scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
-	if (dma_malloc_pages)
-	    scsi_init_free((char *) dma_malloc_pages,
-                           (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages));
-	dma_malloc_pages = NULL;
-	if (dma_malloc_freelist)
-	    scsi_init_free((char *) dma_malloc_freelist,
-                           (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist));
-	dma_malloc_freelist = NULL;
-	dma_sectors = 0;
-	scsi_dma_free_sectors = 0;
-	return;
-    }
-    /* Next, check to see if we need to extend the DMA buffer pool */
+	new_dma_sectors = 2 * SECTORS_PER_PAGE;		/* Base value we use */
+
+	if (__pa(high_memory) - 1 > ISA_DMA_THRESHOLD)
+		need_isa_bounce_buffers = 1;
+	else
+		need_isa_bounce_buffers = 0;
 
-    new_dma_sectors = 2*SECTORS_PER_PAGE;		/* Base value we use */
+	if (scsi_devicelist)
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+			new_dma_sectors += SECTORS_PER_PAGE;	/* Increment for each host */
 
-    if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
-	need_isa_bounce_buffers = 1;
-    else
-	need_isa_bounce_buffers = 0;
-
-    if (scsi_devicelist)
-	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-	    new_dma_sectors += SECTORS_PER_PAGE;	/* Increment for each host */
-
-    for (host = scsi_hostlist; host; host = host->next)
-    {
-        for (SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next) 
-        {
-            /*
-             * sd and sr drivers allocate scatterlists.
-             * sr drivers may allocate for each command 1x2048 or 2x1024 extra
-             * buffers for 2k sector size and 1k fs.
-             * sg driver allocates buffers < 4k.
-             * st driver does not need buffers from the dma pool.
-             * estimate 4k buffer/command for devices of unknown type (should panic).
-             */
-            if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
-                SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
-                new_dma_sectors += ((host->sg_tablesize *
-                                     sizeof(struct scatterlist) + 511) >> 9) *
-                    SDpnt->queue_depth;
-                if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
-                    new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
-            }
-            else if (SDpnt->type == TYPE_SCANNER ||
-                     SDpnt->type == TYPE_PROCESSOR ||
-                     SDpnt->type == TYPE_MEDIUM_CHANGER ||
-                     SDpnt->type == TYPE_ENCLOSURE) {
-                new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
-            }
-            else {
-                if (SDpnt->type != TYPE_TAPE) {
-                    printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
-                    new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
-                }
-            }
-            
-            if(host->unchecked_isa_dma &&
-               need_isa_bounce_buffers &&
-               SDpnt->type != TYPE_TAPE) {
-                new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
-                    SDpnt->queue_depth;
-                new_need_isa_buffer++;
-            }
-        }
-    }
+	for (host = scsi_hostlist; host; host = host->next) {
+		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+			/*
+			 * sd and sr drivers allocate scatterlists.
+			 * sr drivers may allocate for each command 1x2048 or 2x1024 extra
+			 * buffers for 2k sector size and 1k fs.
+			 * sg driver allocates buffers < 4k.
+			 * st driver does not need buffers from the dma pool.
+			 * estimate 4k buffer/command for devices of unknown type (should panic).
+			 */
+			if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
+			    SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
+				new_dma_sectors += ((host->sg_tablesize *
+				sizeof(struct scatterlist) + 511) >> 9) *
+				 SDpnt->queue_depth;
+				if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
+					new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
+			} else if (SDpnt->type == TYPE_SCANNER ||
+				   SDpnt->type == TYPE_PROCESSOR ||
+				   SDpnt->type == TYPE_MEDIUM_CHANGER ||
+				   SDpnt->type == TYPE_ENCLOSURE) {
+				new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+			} else {
+				if (SDpnt->type != TYPE_TAPE) {
+					printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
+					new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+				}
+			}
+
+			if (host->unchecked_isa_dma &&
+			    need_isa_bounce_buffers &&
+			    SDpnt->type != TYPE_TAPE) {
+				new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+				    SDpnt->queue_depth;
+				new_need_isa_buffer++;
+			}
+		}
+	}
 
 #ifdef DEBUG_INIT
-    printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors);
+	printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors);
 #endif
 
-    /* limit DMA memory to 32MB: */
-    new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+	/* limit DMA memory to 32MB: */
+	new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
 
-    /*
-     * We never shrink the buffers - this leads to
-     * race conditions that I would rather not even think
-     * about right now.
-     */
-#if 0  /* Why do this? No gain and risks out_of_space */
-     if( new_dma_sectors < dma_sectors ) 
-	new_dma_sectors = dma_sectors;
-#endif
-    if( new_dma_sectors <= dma_sectors ) 
-	return;	/* best to quit while we are in front */
-
-    for (k = 0; k < 20; ++k) { /* just in case */
-	out_of_space = 0;
-	size = (new_dma_sectors / SECTORS_PER_PAGE) *
-				    sizeof(FreeSectorBitmap);
-	new_dma_malloc_freelist = (FreeSectorBitmap *) 
-			    scsi_init_malloc(size, GFP_ATOMIC);
-	if (new_dma_malloc_freelist) {
-	    size = (new_dma_sectors / SECTORS_PER_PAGE) *
+	/*
+	 * We never shrink the buffers - this leads to
+	 * race conditions that I would rather not even think
+	 * about right now.
+	 */
+#if 0				/* Why do this? No gain and risks out_of_space */
+	if (new_dma_sectors < dma_sectors)
+		new_dma_sectors = dma_sectors;
+#endif
+	if (new_dma_sectors <= dma_sectors)
+		return;		/* best to quit while we are in front */
+
+	for (k = 0; k < 20; ++k) {	/* just in case */
+		out_of_space = 0;
+		size = (new_dma_sectors / SECTORS_PER_PAGE) *
+		    sizeof(FreeSectorBitmap);
+		new_dma_malloc_freelist = (FreeSectorBitmap *)
+		    scsi_init_malloc(size, GFP_ATOMIC);
+		if (new_dma_malloc_freelist) {
+			size = (new_dma_sectors / SECTORS_PER_PAGE) *
 			    sizeof(*new_dma_malloc_pages);
-	    new_dma_malloc_pages = (unsigned char **) 
+			new_dma_malloc_pages = (unsigned char **)
 			    scsi_init_malloc(size, GFP_ATOMIC);
-	    if (! new_dma_malloc_pages) {
-		size = (new_dma_sectors / SECTORS_PER_PAGE) *
+			if (!new_dma_malloc_pages) {
+				size = (new_dma_sectors / SECTORS_PER_PAGE) *
 				    sizeof(FreeSectorBitmap);
-		scsi_init_free((char *)new_dma_malloc_freelist, size);
-		out_of_space = 1;
-	    }
+				scsi_init_free((char *) new_dma_malloc_freelist, size);
+				out_of_space = 1;
+			}
+		} else
+			out_of_space = 1;
+
+		if ((!out_of_space) && (new_dma_sectors > dma_sectors)) {
+			for (i = dma_sectors / SECTORS_PER_PAGE;
+			   i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
+				new_dma_malloc_pages[i] = (unsigned char *)
+				    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+				if (!new_dma_malloc_pages[i])
+					break;
+			}
+			if (i != new_dma_sectors / SECTORS_PER_PAGE) {	/* clean up */
+				int k = i;
+
+				out_of_space = 1;
+				for (i = 0; i < k; ++i)
+					scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE);
+			}
+		}
+		if (out_of_space) {	/* try scaling down new_dma_sectors request */
+			printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
+			       "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
+			if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
+				break;	/* pretty well hopeless ... */
+			new_dma_sectors = (new_dma_sectors * 3) / 4;
+			new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+			if (new_dma_sectors <= dma_sectors)
+				break;	/* stick with what we have got */
+		} else
+			break;	/* found space ... */
+	}			/* end of for loop */
+	if (out_of_space) {
+		scsi_need_isa_buffer = new_need_isa_buffer;	/* some useful info */
+		printk("      WARNING, not enough memory, pool not expanded\n");
+		return;
 	}
-	else
-	    out_of_space = 1;
-	
-	if ((! out_of_space) && (new_dma_sectors > dma_sectors)) { 
-	    for(i = dma_sectors / SECTORS_PER_PAGE; 
-		i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
-		new_dma_malloc_pages[i] = (unsigned char *)
-		    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-		if (! new_dma_malloc_pages[i])
-		    break;
-	    }
-	    if (i != new_dma_sectors / SECTORS_PER_PAGE) { /* clean up */
-		int k = i;
-
-		out_of_space = 1;
-		for (i = 0; i < k; ++i)
-		    scsi_init_free(new_dma_malloc_pages[i], PAGE_SIZE);
-	    }
-	}
-	if (out_of_space) { /* try scaling down new_dma_sectors request */
-	    printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
-		   "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
-	    if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
-		break; /* pretty well hopeless ... */
-	    new_dma_sectors = (new_dma_sectors * 3) / 4;
-	    new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-	    if (new_dma_sectors <= dma_sectors)
-		break; /* stick with what we have got */
+	/* When we dick with the actual DMA list, we need to
+	 * protect things
+	 */
+	if (dma_malloc_freelist) {
+		size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
+		memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size);
+		scsi_init_free((char *) dma_malloc_freelist, size);
 	}
-	else
-	    break; /* found space ... */
-    } /* end of for loop */
-    if (out_of_space) {
-	scsi_need_isa_buffer = new_need_isa_buffer; /* some useful info */
-	printk("      WARNING, not enough memory, pool not expanded\n");
-	return;
-    }
+	dma_malloc_freelist = new_dma_malloc_freelist;
 
-    /* When we dick with the actual DMA list, we need to
-     * protect things
-     */
-    if (dma_malloc_freelist)
-    {
-        size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(FreeSectorBitmap);
-	memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size);
-	scsi_init_free((char *) dma_malloc_freelist, size);
-    }
-    dma_malloc_freelist = new_dma_malloc_freelist;
-
-    if (dma_malloc_pages)
-    {
-        size = (dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages);
-	memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
-	scsi_init_free((char *) dma_malloc_pages, size);
-    }
-
-    scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
-    dma_malloc_pages = new_dma_malloc_pages;
-    dma_sectors = new_dma_sectors;
-    scsi_need_isa_buffer = new_need_isa_buffer;
+	if (dma_malloc_pages) {
+		size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages);
+		memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
+		scsi_init_free((char *) dma_malloc_pages, size);
+	}
+	scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
+	dma_malloc_pages = new_dma_malloc_pages;
+	dma_sectors = new_dma_sectors;
+	scsi_need_isa_buffer = new_need_isa_buffer;
 
 #ifdef DEBUG_INIT
-    printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
-    printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
-    printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
+	printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
+	printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
+	printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
 #endif
 }
 
@@ -2681,175 +2581,157 @@
  */
 static int scsi_register_host(Scsi_Host_Template * tpnt)
 {
-    int pcount;
-    struct Scsi_Host * shpnt;
-    Scsi_Device * SDpnt;
-    struct Scsi_Device_Template * sdtpnt;
-    const char * name;
-    unsigned long flags;
-    int out_of_space = 0;
-
-    if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
-					       * no detect routine available
-					       */
-    pcount = next_scsi_host;
-
-    /* The detect routine must carefully spinunlock/spinlock if 
-       it enables interrupts, since all interrupt handlers do 
-       spinlock as well.
-       All lame drivers are going to fail due to the following 
-       spinlock. For the time beeing let's use it only for drivers 
-       using the new scsi code. NOTE: the detect routine could
-       redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */
-
-    if (tpnt->use_new_eh_code) {
-       spin_lock_irqsave(&io_request_lock, flags);
-       tpnt->present = tpnt->detect(tpnt);
-       spin_unlock_irqrestore(&io_request_lock, flags);
-       }
-    else
-       tpnt->present = tpnt->detect(tpnt);
-
-    if (tpnt->present)
-    {
-	if(pcount == next_scsi_host) 
-        {
-	    if(tpnt->present > 1) 
-            {
-		printk("Failure to register low-level scsi driver");
-		scsi_unregister_host(tpnt);
-		return 1;
-	    }
-	    /* 
-             * The low-level driver failed to register a driver.  We
-	     *  can do this now.
-	     */
-	    scsi_register(tpnt,0);
-	}
-	tpnt->next = scsi_hosts; /* Add to the linked list */
-	scsi_hosts = tpnt;
+	int pcount;
+	struct Scsi_Host *shpnt;
+	Scsi_Device *SDpnt;
+	struct Scsi_Device_Template *sdtpnt;
+	const char *name;
+	unsigned long flags;
+	int out_of_space = 0;
+
+	if (tpnt->next || !tpnt->detect)
+		return 1;	/* Must be already loaded, or
+				 * no detect routine available
+				 */
+	pcount = next_scsi_host;
+
+	/* The detect routine must carefully spinunlock/spinlock if 
+	   it enables interrupts, since all interrupt handlers do 
+	   spinlock as well.
+	   All lame drivers are going to fail due to the following 
+	   spinlock. For the time beeing let's use it only for drivers 
+	   using the new scsi code. NOTE: the detect routine could
+	   redefine the value tpnt->use_new_eh_code. (DB, 13 May 1998) */
+
+	if (tpnt->use_new_eh_code) {
+		spin_lock_irqsave(&io_request_lock, flags);
+		tpnt->present = tpnt->detect(tpnt);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	} else
+		tpnt->present = tpnt->detect(tpnt);
+
+	if (tpnt->present) {
+		if (pcount == next_scsi_host) {
+			if (tpnt->present > 1) {
+				printk("Failure to register low-level scsi driver");
+				scsi_unregister_host(tpnt);
+				return 1;
+			}
+			/* 
+			 * The low-level driver failed to register a driver.  We
+			 *  can do this now.
+			 */
+			scsi_register(tpnt, 0);
+		}
+		tpnt->next = scsi_hosts;	/* Add to the linked list */
+		scsi_hosts = tpnt;
 
-	/* Add the new driver to /proc/scsi */
+		/* Add the new driver to /proc/scsi */
 #if CONFIG_PROC_FS
-	build_proc_dir_entries(tpnt);
+		build_proc_dir_entries(tpnt);
 #endif
 
 
-        /*
-         * Add the kernel threads for each host adapter that will
-         * handle error correction.
-         */
-        for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-        {
-            if( shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code )
-            {
-      		DECLARE_MUTEX_LOCKED(sem);
-                
-                shpnt->eh_notify = &sem;
-                kernel_thread((int (*)(void *))scsi_error_handler, 
-                              (void *) shpnt, 0);
-                
-                /*
-                 * Now wait for the kernel error thread to initialize itself
-                 * as it might be needed when we scan the bus.
-                 */
-                down (&sem);
-                shpnt->eh_notify = NULL;
-            }
-        }
-        
-	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-        {
-	    if(shpnt->hostt == tpnt)
-	    {
-		if(tpnt->info)
-                {
-		    name = tpnt->info(shpnt);
-                }
-		else
-                {
-		    name = tpnt->name;
-                }
-		printk ("scsi%d : %s\n", /* And print a little message */
-			shpnt->host_no, name);
-	    }
-        }
+		/*
+		 * Add the kernel threads for each host adapter that will
+		 * handle error correction.
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code) {
+				DECLARE_MUTEX_LOCKED(sem);
+
+				shpnt->eh_notify = &sem;
+				kernel_thread((int (*)(void *)) scsi_error_handler,
+					      (void *) shpnt, 0);
+
+				/*
+				 * Now wait for the kernel error thread to initialize itself
+				 * as it might be needed when we scan the bus.
+				 */
+				down(&sem);
+				shpnt->eh_notify = NULL;
+			}
+		}
 
-	printk ("scsi : %d host%s.\n", next_scsi_host,
-		(next_scsi_host == 1) ? "" : "s");
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostt == tpnt) {
+				if (tpnt->info) {
+					name = tpnt->info(shpnt);
+				} else {
+					name = tpnt->name;
+				}
+				printk("scsi%d : %s\n",		/* And print a little message */
+				       shpnt->host_no, name);
+			}
+		}
 
-	scsi_make_blocked_list();
+		printk("scsi : %d host%s.\n", next_scsi_host,
+		       (next_scsi_host == 1) ? "" : "s");
 
-	/* The next step is to call scan_scsis here.  This generates the
-	 * Scsi_Devices entries
-	 */
-	for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
-        {
-	    if(shpnt->hostt == tpnt) 
-            {
-		scan_scsis(shpnt,0,0,0,0);
-		if (shpnt->select_queue_depths != NULL)
-		{
-		    (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
+		scsi_make_blocked_list();
+
+		/* The next step is to call scan_scsis here.  This generates the
+		 * Scsi_Devices entries
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			if (shpnt->hostt == tpnt) {
+				scan_scsis(shpnt, 0, 0, 0, 0);
+				if (shpnt->select_queue_depths != NULL) {
+					(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
+				}
+			}
 		}
-	    }
-        }
 
-	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-        {
-	    if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-        }
-
-	/*
-         * Next we create the Scsi_Cmnd structures for this host 
-         */
-        for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-        {
-            for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
-                if(SDpnt->host->hostt == tpnt)
-                {
-                    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-                        if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-                    if(SDpnt->attached) {
-			scsi_build_commandblocks(SDpnt);
-			if (0 == SDpnt->has_cmdblocks)
-			    out_of_space = 1;
-		    }
-                }
-        }
-
-	/*
-	 * Now that we have all of the devices, resize the DMA pool,
-	 * as required.  */
-	if (! out_of_space)
-	    resize_dma_pool();
-
-
-	/* This does any final handling that is required. */
-	for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-        {
-	    if(sdtpnt->finish && sdtpnt->nr_dev)
-            {
-		(*sdtpnt->finish)();
-            }
-        }
-    }
+		for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+			if (sdtpnt->init && sdtpnt->dev_noticed)
+				(*sdtpnt->init) ();
+		}
 
+		/*
+		 * Next we create the Scsi_Cmnd structures for this host 
+		 */
+		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+			for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+				if (SDpnt->host->hostt == tpnt) {
+					for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+						if (sdtpnt->attach)
+							(*sdtpnt->attach) (SDpnt);
+					if (SDpnt->attached) {
+						scsi_build_commandblocks(SDpnt);
+						if (0 == SDpnt->has_cmdblocks)
+							out_of_space = 1;
+					}
+				}
+		}
+
+		/*
+		 * Now that we have all of the devices, resize the DMA pool,
+		 * as required.  */
+		if (!out_of_space)
+			resize_dma_pool();
+
+
+		/* This does any final handling that is required. */
+		for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next) {
+			if (sdtpnt->finish && sdtpnt->nr_dev) {
+				(*sdtpnt->finish) ();
+			}
+		}
+	}
 #if defined(USE_STATIC_SCSI_MEMORY)
-    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+	printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+	       (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+	       (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+	       (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
 #endif
 
-    MOD_INC_USE_COUNT;
+	MOD_INC_USE_COUNT;
 
-    if (out_of_space) {
-	scsi_unregister_host(tpnt); /* easiest way to clean up?? */
-	return 1;
-    }
-    else
-	return 0;
+	if (out_of_space) {
+		scsi_unregister_host(tpnt);	/* easiest way to clean up?? */
+		return 1;
+	} else
+		return 0;
 }
 
 /*
@@ -2864,430 +2746,405 @@
  */
 static void scsi_unregister_host(Scsi_Host_Template * tpnt)
 {
-    int                           online_status;
-    int                           pcount;
-    Scsi_Cmnd                   * SCpnt;
-    Scsi_Device                 * SDpnt;
-    Scsi_Device                 * SDpnt1;
-    struct Scsi_Device_Template * sdtpnt;
-    struct Scsi_Host            * sh1;
-    struct Scsi_Host            * shpnt;
-    Scsi_Host_Template          * SHT;
-    Scsi_Host_Template          * SHTp;
-
-    /*
-     * First verify that this host adapter is completely free with no pending
-     * commands 
-     */
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-            if(SDpnt->host->hostt == tpnt 
-               && SDpnt->host->hostt->module
-               && GET_USE_COUNT(SDpnt->host->hostt->module)) return;
-            /* 
-             * FIXME(eric) - We need to find a way to notify the
-             * low level driver that we are shutting down - via the
-             * special device entry that still needs to get added. 
-             *
-             * Is detach interface below good enough for this?
-             */
-        }
-    }
-
-    /*
-     * FIXME(eric) put a spinlock on this.  We force all of the devices offline
-     * to help prevent race conditions where other hosts/processors could try and
-     * get in and queue a command.
-     */
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-            if(SDpnt->host->hostt == tpnt )
-                SDpnt->online = FALSE;
-
-        }
-    }
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-	if (shpnt->hostt != tpnt)
-        {
-            continue;
-        }
-
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-            /*
-             * Loop over all of the commands associated with the device.  If any of
-             * them are busy, then set the state back to inactive and bail.
-             */
-            for(SCpnt = SDpnt->device_queue; SCpnt; 
-                SCpnt = SCpnt->next)
-	    {
-                online_status = SDpnt->online;
-                SDpnt->online = FALSE;
-	        if(SCpnt->request.rq_status != RQ_INACTIVE) 
-                {
-                    printk("SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n",
-                           SCpnt->request.rq_status, SCpnt->target, SCpnt->pid,
-                           SCpnt->state, SCpnt->owner);
-                    for(SDpnt1 = shpnt->host_queue; SDpnt1; 
-                        SDpnt1 = SDpnt1->next)
-                      {
-                        for(SCpnt = SDpnt1->device_queue; SCpnt; 
-                            SCpnt = SCpnt->next)
-                          if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
-			    SCpnt->request.rq_status = RQ_INACTIVE;
-                      }
-                    SDpnt->online = online_status;
-		    printk("Device busy???\n");
-		    return;
-	        }
-                /*
-                 * No, this device is really free.  Mark it as such, and
-                 * continue on.
-                 */
-                SCpnt->state = SCSI_STATE_DISCONNECTING;
-	        SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;  /* Mark as busy */
-	    }
-        }
-    }
-    /* Next we detach the high level drivers from the Scsi_Device structures */
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        if(shpnt->hostt != tpnt)
-        {
-            continue;
-        }
-
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-	    for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
-              if(sdtpnt->detach) (*sdtpnt->detach)(SDpnt);
-
-            /* If something still attached, punt */
-            if (SDpnt->attached) 
-            {
-                printk("Attached usage count = %d\n", SDpnt->attached);
-                return;
-            }
-	}
-    }
-
-    /*
-     * Next, kill the kernel error recovery thread for this host.
-     */
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        if(   shpnt->hostt == tpnt 
-              && shpnt->hostt->use_new_eh_code
-              && shpnt->ehandler != NULL )
-        {
-            DECLARE_MUTEX_LOCKED(sem);
-            
-            shpnt->eh_notify = &sem;
-            send_sig(SIGKILL, shpnt->ehandler, 1);
-            down(&sem);
-            shpnt->eh_notify = NULL;
-        }
-    }
-
-    /* Next we free up the Scsi_Cmnd structures for this host */
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-	if(shpnt->hostt != tpnt)
-        {
-            continue;
-        }
-
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = shpnt->host_queue)
-        {
-            while (SDpnt->device_queue)
-            {
-                SCpnt = SDpnt->device_queue->next;
-                scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd));
-                SDpnt->device_queue = SCpnt;
-            }
-            SDpnt->has_cmdblocks = 0;
-
-            /* Next free up the Scsi_Device structures for this host */
-            shpnt->host_queue = SDpnt->next;
-	    scsi_init_free((char *) SDpnt, sizeof (Scsi_Device));
-
-        }
-    }
-
-    /* Next we go through and remove the instances of the individual hosts
-     * that were detected */
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = sh1) 
-    {
-	sh1 = shpnt->next;
-	if(shpnt->hostt == tpnt) {
-	    if(shpnt->loaded_as_module) {
-		pcount = next_scsi_host;
-	        /* Remove the /proc/scsi directory entry */
+	int online_status;
+	int pcount;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+	Scsi_Device *SDpnt1;
+	struct Scsi_Device_Template *sdtpnt;
+	struct Scsi_Host *sh1;
+	struct Scsi_Host *shpnt;
+	Scsi_Host_Template *SHT;
+	Scsi_Host_Template *SHTp;
+
+	/*
+	 * First verify that this host adapter is completely free with no pending
+	 * commands 
+	 */
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			if (SDpnt->host->hostt == tpnt
+			    && SDpnt->host->hostt->module
+			    && GET_USE_COUNT(SDpnt->host->hostt->module))
+				return;
+			/* 
+			 * FIXME(eric) - We need to find a way to notify the
+			 * low level driver that we are shutting down - via the
+			 * special device entry that still needs to get added. 
+			 *
+			 * Is detach interface below good enough for this?
+			 */
+		}
+	}
+
+	/*
+	 * FIXME(eric) put a spinlock on this.  We force all of the devices offline
+	 * to help prevent race conditions where other hosts/processors could try and
+	 * get in and queue a command.
+	 */
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			if (SDpnt->host->hostt == tpnt)
+				SDpnt->online = FALSE;
+
+		}
+	}
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		if (shpnt->hostt != tpnt) {
+			continue;
+		}
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			/*
+			 * Loop over all of the commands associated with the device.  If any of
+			 * them are busy, then set the state back to inactive and bail.
+			 */
+			for (SCpnt = SDpnt->device_queue; SCpnt;
+			     SCpnt = SCpnt->next) {
+				online_status = SDpnt->online;
+				SDpnt->online = FALSE;
+				if (SCpnt->request.rq_status != RQ_INACTIVE) {
+					printk("SCSI device not inactive - rq_status=%d, target=%d, pid=%ld, state=%d, owner=%d.\n",
+					       SCpnt->request.rq_status, SCpnt->target, SCpnt->pid,
+					     SCpnt->state, SCpnt->owner);
+					for (SDpnt1 = shpnt->host_queue; SDpnt1;
+					     SDpnt1 = SDpnt1->next) {
+						for (SCpnt = SDpnt1->device_queue; SCpnt;
+						     SCpnt = SCpnt->next)
+							if (SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
+								SCpnt->request.rq_status = RQ_INACTIVE;
+					}
+					SDpnt->online = online_status;
+					printk("Device busy???\n");
+					return;
+				}
+				/*
+				 * No, this device is really free.  Mark it as such, and
+				 * continue on.
+				 */
+				SCpnt->state = SCSI_STATE_DISCONNECTING;
+				SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING;	/* Mark as busy */
+			}
+		}
+	}
+	/* Next we detach the high level drivers from the Scsi_Device structures */
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		if (shpnt->hostt != tpnt) {
+			continue;
+		}
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+				if (sdtpnt->detach)
+					(*sdtpnt->detach) (SDpnt);
+
+			/* If something still attached, punt */
+			if (SDpnt->attached) {
+				printk("Attached usage count = %d\n", SDpnt->attached);
+				return;
+			}
+		}
+	}
+
+	/*
+	 * Next, kill the kernel error recovery thread for this host.
+	 */
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		if (shpnt->hostt == tpnt
+		    && shpnt->hostt->use_new_eh_code
+		    && shpnt->ehandler != NULL) {
+			DECLARE_MUTEX_LOCKED(sem);
+
+			shpnt->eh_notify = &sem;
+			send_sig(SIGKILL, shpnt->ehandler, 1);
+			down(&sem);
+			shpnt->eh_notify = NULL;
+		}
+	}
+
+	/* Next we free up the Scsi_Cmnd structures for this host */
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		if (shpnt->hostt != tpnt) {
+			continue;
+		}
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = shpnt->host_queue) {
+			while (SDpnt->device_queue) {
+				SCpnt = SDpnt->device_queue->next;
+				scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd));
+				SDpnt->device_queue = SCpnt;
+			}
+			SDpnt->has_cmdblocks = 0;
+
+			/* Next free up the Scsi_Device structures for this host */
+			shpnt->host_queue = SDpnt->next;
+			scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
+
+		}
+	}
+
+	/* Next we go through and remove the instances of the individual hosts
+	 * that were detected */
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = sh1) {
+		sh1 = shpnt->next;
+		if (shpnt->hostt == tpnt) {
+			if (shpnt->loaded_as_module) {
+				pcount = next_scsi_host;
+				/* Remove the /proc/scsi directory entry */
 #if CONFIG_PROC_FS
-	        proc_scsi_unregister(tpnt->proc_dir,
-	                             shpnt->host_no + PROC_SCSI_FILE);
+				proc_scsi_unregister(tpnt->proc_dir,
+					shpnt->host_no + PROC_SCSI_FILE);
 #endif
-		if(tpnt->release)
-		    (*tpnt->release)(shpnt);
-		else {
-		    /* This is the default case for the release function.
-		     * It should do the right thing for most correctly
-		     * written host adapters.
-		     */
-		    if (shpnt->irq) free_irq(shpnt->irq, NULL);
-		    if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
-		    if (shpnt->io_port && shpnt->n_io_port)
-			release_region(shpnt->io_port, shpnt->n_io_port);
-		}
-		if(pcount == next_scsi_host) scsi_unregister(shpnt);
-		tpnt->present--;
-	    }
-	}
-    }
-
-    /*
-     * If there are absolutely no more hosts left, it is safe
-     * to completely nuke the DMA pool.  The resize operation will
-     * do the right thing and free everything.
-     */
-    if( !scsi_hosts )
-	resize_dma_pool();
+				if (tpnt->release)
+					(*tpnt->release) (shpnt);
+				else {
+					/* This is the default case for the release function.
+					 * It should do the right thing for most correctly
+					 * written host adapters.
+					 */
+					if (shpnt->irq)
+						free_irq(shpnt->irq, NULL);
+					if (shpnt->dma_channel != 0xff)
+						free_dma(shpnt->dma_channel);
+					if (shpnt->io_port && shpnt->n_io_port)
+						release_region(shpnt->io_port, shpnt->n_io_port);
+				}
+				if (pcount == next_scsi_host)
+					scsi_unregister(shpnt);
+				tpnt->present--;
+			}
+		}
+	}
+
+	/*
+	 * If there are absolutely no more hosts left, it is safe
+	 * to completely nuke the DMA pool.  The resize operation will
+	 * do the right thing and free everything.
+	 */
+	if (!scsi_hosts)
+		resize_dma_pool();
 
-    printk ("scsi : %d host%s.\n", next_scsi_host,
-	    (next_scsi_host == 1) ? "" : "s");
+	printk("scsi : %d host%s.\n", next_scsi_host,
+	       (next_scsi_host == 1) ? "" : "s");
 
 #if defined(USE_STATIC_SCSI_MEMORY)
-    printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
-	    (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
-	    (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
-	    (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
-#endif
-
-    scsi_make_blocked_list();
-
-    /* There were some hosts that were loaded at boot time, so we cannot
-       do any more than this */
-    if (tpnt->present) return;
-
-    /* OK, this is the very last step.  Remove this host adapter from the
-       linked list. */
-    for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
-	if(SHT == tpnt) {
-	    if(SHTp)
-		SHTp->next = SHT->next;
-	    else
-		scsi_hosts = SHT->next;
-	    SHT->next = NULL;
-	    break;
-	}
+	printk("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+	       (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+	       (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+	       (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+#endif
 
-    /* Rebuild the /proc/scsi directory entries */
+	scsi_make_blocked_list();
+
+	/* There were some hosts that were loaded at boot time, so we cannot
+	   do any more than this */
+	if (tpnt->present)
+		return;
+
+	/* OK, this is the very last step.  Remove this host adapter from the
+	   linked list. */
+	for (SHTp = NULL, SHT = scsi_hosts; SHT; SHTp = SHT, SHT = SHT->next)
+		if (SHT == tpnt) {
+			if (SHTp)
+				SHTp->next = SHT->next;
+			else
+				scsi_hosts = SHT->next;
+			SHT->next = NULL;
+			break;
+		}
+	/* Rebuild the /proc/scsi directory entries */
 #if CONFIG_PROC_FS
-    proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino);
+	proc_scsi_unregister(tpnt->proc_dir, tpnt->proc_dir->low_ino);
 #endif
-    MOD_DEC_USE_COUNT;
+	MOD_DEC_USE_COUNT;
 }
 
 /*
  * This entry point should be called by a loadable module if it is trying
  * add a high level scsi driver to the system.
  */
-static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
+static int scsi_register_device_module(struct Scsi_Device_Template *tpnt)
 {
-    Scsi_Device      * SDpnt;
-    struct Scsi_Host * shpnt;
-    int out_of_space = 0;
-
-    if (tpnt->next) return 1;
-
-    scsi_register_device(tpnt);
-    /*
-     * First scan the devices that we know about, and see if we notice them.
-     */
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-            if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
-        }
-    }
-
-    /*
-     * If any of the devices would match this driver, then perform the
-     * init function.
-     */
-    if(tpnt->init && tpnt->dev_noticed)
-	if ((*tpnt->init)()) return 1;
-
-    /*
-     * Now actually connect the devices to the new driver.
-     */
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-            if(tpnt->attach)  (*tpnt->attach)(SDpnt);
-            /*
-             * If this driver attached to the device, and don't have any
-             * command blocks for this device, allocate some.
-             */
-            if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
-            {
-                SDpnt->online = TRUE;
-                scsi_build_commandblocks(SDpnt);
-		if (0 == SDpnt->has_cmdblocks)
-		    out_of_space = 1;
-            }
-        }
-    }
-
-    /*
-     * This does any final handling that is required.
-     */
-    if(tpnt->finish && tpnt->nr_dev)  (*tpnt->finish)();
-    if (! out_of_space)
-	resize_dma_pool();
-    MOD_INC_USE_COUNT;
+	Scsi_Device *SDpnt;
+	struct Scsi_Host *shpnt;
+	int out_of_space = 0;
 
-    if (out_of_space) {
-	scsi_unregister_device(tpnt); /* easiest way to clean up?? */
-	return 1;
-    }
-    else
+	if (tpnt->next)
+		return 1;
+
+	scsi_register_device(tpnt);
+	/*
+	 * First scan the devices that we know about, and see if we notice them.
+	 */
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			if (tpnt->detect)
+				SDpnt->attached += (*tpnt->detect) (SDpnt);
+		}
+	}
+
+	/*
+	 * If any of the devices would match this driver, then perform the
+	 * init function.
+	 */
+	if (tpnt->init && tpnt->dev_noticed)
+		if ((*tpnt->init) ())
+			return 1;
+
+	/*
+	 * Now actually connect the devices to the new driver.
+	 */
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			if (tpnt->attach)
+				(*tpnt->attach) (SDpnt);
+			/*
+			 * If this driver attached to the device, and don't have any
+			 * command blocks for this device, allocate some.
+			 */
+			if (SDpnt->attached && SDpnt->has_cmdblocks == 0) {
+				SDpnt->online = TRUE;
+				scsi_build_commandblocks(SDpnt);
+				if (0 == SDpnt->has_cmdblocks)
+					out_of_space = 1;
+			}
+		}
+	}
+
+	/*
+	 * This does any final handling that is required.
+	 */
+	if (tpnt->finish && tpnt->nr_dev)
+		(*tpnt->finish) ();
+	if (!out_of_space)
+		resize_dma_pool();
+	MOD_INC_USE_COUNT;
+
+	if (out_of_space) {
+		scsi_unregister_device(tpnt);	/* easiest way to clean up?? */
+		return 1;
+	} else
+		return 0;
+}
+
+static int scsi_unregister_device(struct Scsi_Device_Template *tpnt)
+{
+	Scsi_Device *SDpnt;
+	Scsi_Cmnd *SCpnt;
+	struct Scsi_Host *shpnt;
+	struct Scsi_Device_Template *spnt;
+	struct Scsi_Device_Template *prev_spnt;
+
+	/*
+	 * If we are busy, this is not going to fly.
+	 */
+	if (GET_USE_COUNT(tpnt->module) != 0)
+		return 0;
+
+	/*
+	 * Next, detach the devices from the driver.
+	 */
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt;
+		     SDpnt = SDpnt->next) {
+			if (tpnt->detach)
+				(*tpnt->detach) (SDpnt);
+			if (SDpnt->attached == 0) {
+				SDpnt->online = FALSE;
+
+				/*
+				 * Nobody is using this device any more.  Free all of the
+				 * command structures.
+				 */
+				for (SCpnt = SDpnt->device_queue; SCpnt;
+				     SCpnt = SCpnt->next) {
+					if (SCpnt == SDpnt->device_queue)
+						SDpnt->device_queue = SCpnt->next;
+					scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
+				}
+				SDpnt->has_cmdblocks = 0;
+			}
+		}
+	}
+	/*
+	 * Extract the template from the linked list.
+	 */
+	spnt = scsi_devicelist;
+	prev_spnt = NULL;
+	while (spnt != tpnt) {
+		prev_spnt = spnt;
+		spnt = spnt->next;
+	}
+	if (prev_spnt == NULL)
+		scsi_devicelist = tpnt->next;
+	else
+		prev_spnt->next = spnt->next;
+
+	MOD_DEC_USE_COUNT;
+	/*
+	 * Final cleanup for the driver is done in the driver sources in the
+	 * cleanup function.
+	 */
 	return 0;
 }
 
-static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
+
+int scsi_register_module(int module_type, void *ptr)
 {
-    Scsi_Device * SDpnt;
-    Scsi_Cmnd * SCpnt;
-    struct Scsi_Host * shpnt;
-    struct Scsi_Device_Template * spnt;
-    struct Scsi_Device_Template * prev_spnt;
-
-    /*
-     * If we are busy, this is not going to fly.
-     */
-    if(GET_USE_COUNT(tpnt->module) != 0) return 0;
-
-    /*
-     * Next, detach the devices from the driver.
-     */
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        for(SDpnt = shpnt->host_queue; SDpnt; 
-            SDpnt = SDpnt->next)
-        {
-            if(tpnt->detach) (*tpnt->detach)(SDpnt);
-	    if(SDpnt->attached == 0)
-	    {
-                SDpnt->online = FALSE;
-
-                /*
-	         * Nobody is using this device any more.  Free all of the
-	         * command structures.
-	         */
-	        for(SCpnt = SDpnt->device_queue; SCpnt; 
-                    SCpnt = SCpnt->next)
-	        {
-		    if(SCpnt == SDpnt->device_queue)
-			SDpnt->device_queue = SCpnt->next;
-		    scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
-	        }
-	        SDpnt->has_cmdblocks = 0;
-	    }
-        }
-    }
-    /*
-     * Extract the template from the linked list.
-     */
-    spnt = scsi_devicelist;
-    prev_spnt = NULL;
-    while(spnt != tpnt)
-    {
-	prev_spnt = spnt;
-	spnt = spnt->next;
-    }
-    if(prev_spnt == NULL)
-	scsi_devicelist = tpnt->next;
-    else
-	prev_spnt->next = spnt->next;
-
-    MOD_DEC_USE_COUNT;
-    /*
-     * Final cleanup for the driver is done in the driver sources in the
-     * cleanup function.
-     */
-    return 0;
-}
-
-
-int scsi_register_module(int module_type, void * ptr)
-{
-    switch(module_type)
-    {
-    case MODULE_SCSI_HA:
-	return scsi_register_host((Scsi_Host_Template *) ptr);
-        
-	/* Load upper level device handler of some kind */
-    case MODULE_SCSI_DEV:
+	switch (module_type) {
+	case MODULE_SCSI_HA:
+		return scsi_register_host((Scsi_Host_Template *) ptr);
+
+		/* Load upper level device handler of some kind */
+	case MODULE_SCSI_DEV:
 #ifdef CONFIG_KMOD
-	if (scsi_hosts == NULL)
-            request_module("scsi_hostadapter");
+		if (scsi_hosts == NULL)
+			request_module("scsi_hostadapter");
 #endif
-	return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
-	/* The rest of these are not yet implemented */
-        
-	/* Load constants.o */
-    case MODULE_SCSI_CONST:
-        
-	/* Load specialized ioctl handler for some device.  Intended for
-	 * cdroms that have non-SCSI2 audio command sets. */
-    case MODULE_SCSI_IOCTL:
-        
-    default:
-	return 1;
-    }
+		return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
+		/* The rest of these are not yet implemented */
+
+		/* Load constants.o */
+	case MODULE_SCSI_CONST:
+
+		/* Load specialized ioctl handler for some device.  Intended for
+		 * cdroms that have non-SCSI2 audio command sets. */
+	case MODULE_SCSI_IOCTL:
+
+	default:
+		return 1;
+	}
 }
 
-void scsi_unregister_module(int module_type, void * ptr)
+void scsi_unregister_module(int module_type, void *ptr)
 {
-    switch(module_type) 
-    {
-    case MODULE_SCSI_HA:
-	scsi_unregister_host((Scsi_Host_Template *) ptr);
-	break;
-    case MODULE_SCSI_DEV:
-	scsi_unregister_device((struct Scsi_Device_Template *) ptr);
-	break;
-	/* The rest of these are not yet implemented. */
-    case MODULE_SCSI_CONST:
-    case MODULE_SCSI_IOCTL:
-	break;
-    default:
-    }
-    return;
+	switch (module_type) {
+	case MODULE_SCSI_HA:
+		scsi_unregister_host((Scsi_Host_Template *) ptr);
+		break;
+	case MODULE_SCSI_DEV:
+		scsi_unregister_device((struct Scsi_Device_Template *) ptr);
+		break;
+		/* The rest of these are not yet implemented. */
+	case MODULE_SCSI_CONST:
+	case MODULE_SCSI_IOCTL:
+		break;
+	default:
+	}
+	return;
 }
 
-#endif		/* CONFIG_MODULES */
+#endif				/* CONFIG_MODULES */
 
 /*
  * Function:    scsi_dump_status
@@ -3307,183 +3164,173 @@
  *
  *              FIXME - some formatting of the output into tables would be very handy.
  */
-static void
-scsi_dump_status(int level)
+static void scsi_dump_status(int level)
 {
 #if CONFIG_PROC_FS
-#if CONFIG_SCSI_LOGGING /* { */
-    int i;
-    struct Scsi_Host * shpnt;
-    Scsi_Cmnd * SCpnt;
-    Scsi_Device * SDpnt;
-    printk("Dump of scsi host parameters:\n");
-    i = 0;
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        printk(" %d %d %d : %d %p\n",
-               shpnt->host_failed,
-               shpnt->host_busy,
-               atomic_read(&shpnt->host_active),
-               shpnt->host_blocked,
-               shpnt->pending_commands);
-
-    }
-
-    printk("\n\n");
-    printk("Dump of scsi command parameters:\n");
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-        printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
-	for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
-	{
-            for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-            {
-                /*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
-                printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
-                       i++, 
-
-                       SCpnt->host->host_no,
-                       SCpnt->channel,
-                       SCpnt->target,
-                       SCpnt->lun,
-
-                       kdevname(SCpnt->request.rq_dev),
-                       SCpnt->request.sector,
-                       SCpnt->request.nr_sectors,
-                       SCpnt->request.current_nr_sectors,
-                       SCpnt->request.rq_status,
-                       SCpnt->use_sg,
-
-                       SCpnt->retries,
-                       SCpnt->allowed,
-                       SCpnt->flags,
-
-                       SCpnt->timeout_per_command,
-                       SCpnt->timeout,
-                       SCpnt->internal_timeout,
-
-                       SCpnt->cmnd[0],
-                       SCpnt->sense_buffer[2],
-                       SCpnt->result);
-            }
-        }
-    }
-
-    for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
-    {
-	for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
-	{
-            /* Now dump the request lists for each block device */
-            printk("Dump of pending block device requests\n");
-            for(i=0; i<MAX_BLKDEV; i++)
-            {
-                if(blk_dev[i].current_request)
-                {
-                    struct request * req;
-                    printk("%d: ", i);
-                    req = blk_dev[i].current_request;
-                    while(req) 
-                    {
-                        printk("(%s %d %ld %ld %ld) ",
-                               kdevname(req->rq_dev),
-                               req->cmd,
-                               req->sector,
-                               req->nr_sectors,
-                               req->current_nr_sectors);
-                        req = req->next;
-                    }
-                    printk("\n");
-                }
-            }
-        }
-    }
-    printk("wait_for_request = %p\n", wait_for_request);
-#endif /* CONFIG_SCSI_LOGGING */ /* } */
-#endif /* CONFIG_PROC_FS */
+#if CONFIG_SCSI_LOGGING		/* { */
+	int i;
+	struct Scsi_Host *shpnt;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+	printk("Dump of scsi host parameters:\n");
+	i = 0;
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		printk(" %d %d %d : %d %p\n",
+		       shpnt->host_failed,
+		       shpnt->host_busy,
+		       atomic_read(&shpnt->host_active),
+		       shpnt->host_blocked,
+		       shpnt->pending_commands);
+
+	}
+
+	printk("\n\n");
+	printk("Dump of scsi command parameters:\n");
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
+		for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
+			for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+				/*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
+				printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
+				       i++,
+
+				       SCpnt->host->host_no,
+				       SCpnt->channel,
+				       SCpnt->target,
+				       SCpnt->lun,
+
+				       kdevname(SCpnt->request.rq_dev),
+				       SCpnt->request.sector,
+				       SCpnt->request.nr_sectors,
+				       SCpnt->request.current_nr_sectors,
+				       SCpnt->request.rq_status,
+				       SCpnt->use_sg,
+
+				       SCpnt->retries,
+				       SCpnt->allowed,
+				       SCpnt->flags,
+
+				       SCpnt->timeout_per_command,
+				       SCpnt->timeout,
+				       SCpnt->internal_timeout,
+
+				       SCpnt->cmnd[0],
+				       SCpnt->sense_buffer[2],
+				       SCpnt->result);
+			}
+		}
+	}
+
+	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
+		for (SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next) {
+			/* Now dump the request lists for each block device */
+			printk("Dump of pending block device requests\n");
+			for (i = 0; i < MAX_BLKDEV; i++) {
+				if (blk_dev[i].current_request) {
+					struct request *req;
+					printk("%d: ", i);
+					req = blk_dev[i].current_request;
+					while (req) {
+						printk("(%s %d %ld %ld %ld) ",
+						   kdevname(req->rq_dev),
+						       req->cmd,
+						       req->sector,
+						       req->nr_sectors,
+						req->current_nr_sectors);
+						req = req->next;
+					}
+					printk("\n");
+				}
+			}
+		}
+	}
+	printk("wait_for_request = %p\n", wait_for_request);
+#endif	/* CONFIG_SCSI_LOGGING */ /* } */
+#endif				/* CONFIG_PROC_FS */
 }
 
 #ifdef MODULE
 
-int init_module(void) 
+int init_module(void)
 {
-    unsigned long size;
-    int has_space = 0;
+	unsigned long size;
+	int has_space = 0;
 
-    /*
-     * This makes /proc/scsi visible.
-     */
+	/*
+	 * This makes /proc/scsi visible.
+	 */
 #if CONFIG_PROC_FS
-    dispatch_scsi_info_ptr = dispatch_scsi_info;
+	dispatch_scsi_info_ptr = dispatch_scsi_info;
 #endif
 
-    scsi_loadable_module_flag = 1;
+	scsi_loadable_module_flag = 1;
 
-    /* Register the /proc/scsi/scsi entry */
+	/* Register the /proc/scsi/scsi entry */
 #if CONFIG_PROC_FS
-    proc_scsi_register(0, &proc_scsi_scsi);
+	proc_scsi_register(0, &proc_scsi_scsi);
 #endif
 
-    dma_sectors = PAGE_SIZE / SECTOR_SIZE;
-    scsi_dma_free_sectors= dma_sectors;
-    /*
-     * Set up a minimal DMA buffer list - this will be used during scan_scsis
-     * in some cases.
-     */
-
-    /* One bit per sector to indicate free/busy */
-    size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
-    dma_malloc_freelist = (FreeSectorBitmap *) 
-				scsi_init_malloc(size, GFP_ATOMIC);
-    if (dma_malloc_freelist) {
-	/* One pointer per page for the page list */
-	dma_malloc_pages = (unsigned char **)scsi_init_malloc(
-		(dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
-							      GFP_ATOMIC);
-	if (dma_malloc_pages) {
-	    dma_malloc_pages[0] = (unsigned char *)
-			scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-	    if (dma_malloc_pages[0])
-		has_space = 1;
-	}
-    }
-    if (! has_space) {
+	dma_sectors = PAGE_SIZE / SECTOR_SIZE;
+	scsi_dma_free_sectors = dma_sectors;
+	/*
+	 * Set up a minimal DMA buffer list - this will be used during scan_scsis
+	 * in some cases.
+	 */
+
+	/* One bit per sector to indicate free/busy */
+	size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
+	dma_malloc_freelist = (FreeSectorBitmap *)
+	    scsi_init_malloc(size, GFP_ATOMIC);
 	if (dma_malloc_freelist) {
-	    scsi_init_free((char *)dma_malloc_freelist, size);
-	    if (dma_malloc_pages)
-		scsi_init_free((char *)dma_malloc_pages,
-		(dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
+		/* One pointer per page for the page list */
+		dma_malloc_pages = (unsigned char **) scsi_init_malloc(
+									      (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
+							     GFP_ATOMIC);
+		if (dma_malloc_pages) {
+			dma_malloc_pages[0] = (unsigned char *)
+			    scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+			if (dma_malloc_pages[0])
+				has_space = 1;
+		}
 	}
-	printk("scsi::init_module: failed, out of memory\n");
-	return 1;
-    }
-
-    /*
-     * This is where the processing takes place for most everything
-     * when commands are completed.
-     */
-    init_bh(SCSI_BH, scsi_bottom_half_handler);
+	if (!has_space) {
+		if (dma_malloc_freelist) {
+			scsi_init_free((char *) dma_malloc_freelist, size);
+			if (dma_malloc_pages)
+				scsi_init_free((char *) dma_malloc_pages,
+					       (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages));
+		}
+		printk("scsi::init_module: failed, out of memory\n");
+		return 1;
+	}
+	/*
+	 * This is where the processing takes place for most everything
+	 * when commands are completed.
+	 */
+	init_bh(SCSI_BH, scsi_bottom_half_handler);
 
-    return 0;
+	return 0;
 }
 
-void cleanup_module( void)
+void cleanup_module(void)
 {
-    remove_bh(SCSI_BH);
+	remove_bh(SCSI_BH);
 
 #if CONFIG_PROC_FS
-    proc_scsi_unregister(0, PROC_SCSI_SCSI);
+	proc_scsi_unregister(0, PROC_SCSI_SCSI);
 
-    /* No, we're not here anymore. Don't show the /proc/scsi files. */
-    dispatch_scsi_info_ptr = 0L;
+	/* No, we're not here anymore. Don't show the /proc/scsi files. */
+	dispatch_scsi_info_ptr = 0L;
 #endif
 
-    /*
-     * Free up the DMA pool.
-     */
-    resize_dma_pool();
+	/*
+	 * Free up the DMA pool.
+	 */
+	resize_dma_pool();
 
 }
-#endif /* MODULE */
+
+#endif				/* MODULE */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h
--- v2.3.16/linux/drivers/scsi/scsi.h	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/scsi.h	Tue Sep  7 11:50:56 1999
@@ -15,7 +15,7 @@
 #ifndef _SCSI_H
 #define _SCSI_H
 
-#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
+#include <linux/config.h>	/* for CONFIG_SCSI_LOGGING */
 
 /*
  * Some of the public constants are being moved to this file.
@@ -33,19 +33,19 @@
  * Some defs, in case these are not defined elsewhere.
  */
 #ifndef TRUE
-# define TRUE 1
+#define TRUE 1
 #endif
 #ifndef FALSE
-# define FALSE 0
+#define FALSE 0
 #endif
 
 #define MAX_SCSI_DEVICE_CODE 14
 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 
 #ifdef DEBUG
-    #define SCSI_TIMEOUT (5*HZ)
+#define SCSI_TIMEOUT (5*HZ)
 #else
-    #define SCSI_TIMEOUT (2*HZ)
+#define SCSI_TIMEOUT (2*HZ)
 #endif
 
 /*
@@ -104,9 +104,9 @@
 #define IDENTIFY_BASE       0x80
 #define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
 		     ((can_disconnect) ?  0x40 : 0) |\
-		     ((lun) & 0x07)) 
+		     ((lun) & 0x07))
+
 
-		 
 /*
  * This defines the scsi logging feature.  It is a means by which the
  * user can select how much information they get about various goings on,
@@ -205,7 +205,7 @@
         SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
 #define SCSI_LOG_IOCTL(LEVEL,CMD)  \
         SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
-    
+
 
 #define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL)  \
         SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
@@ -227,7 +227,7 @@
         SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
 #define SCSI_SET_IOCTL_LOGGING(LEVEL)  \
         SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
-    
+
 /*
  *  the return of the status word will be in the following format :
  *  The low byte is the status returned by the SCSI command, 
@@ -248,19 +248,19 @@
  */
 
 
-#define DID_OK          0x00 /* NO error                                */
-#define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
-#define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
-#define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
-#define DID_BAD_TARGET  0x04 /* BAD target.                             */
-#define DID_ABORT       0x05 /* Told to abort for some other reason     */
-#define DID_PARITY      0x06 /* Parity error                            */
-#define DID_ERROR       0x07 /* Internal error                          */
-#define DID_RESET       0x08 /* Reset by somebody.                      */
-#define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */ 
-#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
-#define DID_SOFT_ERROR  0x0b /* The low level driver just wish a retry  */
-#define DRIVER_OK       0x00 /* Driver status                           */ 
+#define DID_OK          0x00	/* NO error                                */
+#define DID_NO_CONNECT  0x01	/* Couldn't connect before timeout period  */
+#define DID_BUS_BUSY    0x02	/* BUS stayed busy through time out period */
+#define DID_TIME_OUT    0x03	/* TIMED OUT for other reason              */
+#define DID_BAD_TARGET  0x04	/* BAD target.                             */
+#define DID_ABORT       0x05	/* Told to abort for some other reason     */
+#define DID_PARITY      0x06	/* Parity error                            */
+#define DID_ERROR       0x07	/* Internal error                          */
+#define DID_RESET       0x08	/* Reset by somebody.                      */
+#define DID_BAD_INTR    0x09	/* Got an interrupt we weren't expecting.  */
+#define DID_PASSTHROUGH 0x0a	/* Force command past mid-layer            */
+#define DID_SOFT_ERROR  0x0b	/* The low level driver just wish a retry  */
+#define DRIVER_OK       0x00	/* Driver status                           */
 
 /*
  *  These indicate the error that occurred, and what is available.
@@ -269,7 +269,7 @@
 #define DRIVER_BUSY         0x01
 #define DRIVER_SOFT         0x02
 #define DRIVER_MEDIA        0x03
-#define DRIVER_ERROR        0x04    
+#define DRIVER_ERROR        0x04
 
 #define DRIVER_INVALID      0x05
 #define DRIVER_TIMEOUT      0x06
@@ -277,7 +277,7 @@
 #define DRIVER_SENSE	    0x08
 
 #define SUGGEST_RETRY       0x10
-#define SUGGEST_ABORT       0x20 
+#define SUGGEST_ABORT       0x20
 #define SUGGEST_REMAP       0x30
 #define SUGGEST_DIE         0x40
 #define SUGGEST_SENSE       0x80
@@ -339,7 +339,7 @@
  * Add some typedefs so that we can prototyope a bunch of the functions.
  */
 typedef struct scsi_device Scsi_Device;
-typedef struct scsi_cmnd   Scsi_Cmnd;
+typedef struct scsi_cmnd Scsi_Cmnd;
 
 /*
  * Here is where we prototype most of the mid-layer.
@@ -347,18 +347,18 @@
 
 /*
  *  Initializes all SCSI devices.  This scans all scsi busses.
- */ 
+ */
 
-extern int scsi_dev_init (void);
+extern int scsi_dev_init(void);
 
 
 
-void *   scsi_malloc(unsigned int);
-int      scsi_free(void *, unsigned int);
-extern unsigned int scsi_logging_level; /* What do we log? */
-extern unsigned int scsi_dma_free_sectors;  /* How much room do we have left */
-extern unsigned int scsi_need_isa_buffer;   /* True if some devices need indirection
-					* buffers */
+void *scsi_malloc(unsigned int);
+int scsi_free(void *, unsigned int);
+extern unsigned int scsi_logging_level;		/* What do we log? */
+extern unsigned int scsi_dma_free_sectors;	/* How much room do we have left */
+extern unsigned int scsi_need_isa_buffer;	/* True if some devices need indirection
+						   * buffers */
 extern void scsi_make_blocked_list(void);
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
@@ -366,16 +366,16 @@
 /*
  * These are the error handling functions defined in scsi_error.c
  */
-extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout, 
-                                void (*complete)(Scsi_Cmnd *));
-extern void scsi_done (Scsi_Cmnd *SCpnt);
-extern int  scsi_delete_timer(Scsi_Cmnd * SCset);
-extern void scsi_error_handler(void * host);
-extern int  scsi_retry_command(Scsi_Cmnd *);
+extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout,
+			   void (*complete) (Scsi_Cmnd *));
+extern void scsi_done(Scsi_Cmnd * SCpnt);
+extern int scsi_delete_timer(Scsi_Cmnd * SCset);
+extern void scsi_error_handler(void *host);
+extern int scsi_retry_command(Scsi_Cmnd *);
 extern void scsi_finish_command(Scsi_Cmnd *);
-extern int  scsi_sense_valid(Scsi_Cmnd *);
-extern int  scsi_decide_disposition (Scsi_Cmnd * SCpnt);
-extern int  scsi_block_when_processing_errors(Scsi_Device *);
+extern int scsi_sense_valid(Scsi_Cmnd *);
+extern int scsi_decide_disposition(Scsi_Cmnd * SCpnt);
+extern int scsi_block_when_processing_errors(Scsi_Device *);
 extern void scsi_sleep(int);
 
 /*
@@ -384,15 +384,15 @@
  *  DID_ABORT is returned in the hostbyte.
  */
 
-extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
-			 void *buffer, unsigned bufflen, 
-			 void (*done)(struct scsi_cmnd *),
-			 int timeout, int retries);
+extern void scsi_do_cmd(Scsi_Cmnd *, const void *cmnd,
+			void *buffer, unsigned bufflen,
+			void (*done) (struct scsi_cmnd *),
+			int timeout, int retries);
 
 
-extern Scsi_Cmnd * scsi_allocate_device(struct request **, Scsi_Device *, int);
+extern Scsi_Cmnd *scsi_allocate_device(struct request **, Scsi_Device *, int);
 
-extern Scsi_Cmnd * scsi_request_queueable(struct request *, Scsi_Device *);
+extern Scsi_Cmnd *scsi_request_queueable(struct request *, Scsi_Device *);
 
 extern void scsi_release_command(Scsi_Cmnd *);
 
@@ -412,62 +412,62 @@
 
 struct scsi_device {
 /* private: */
-    /*
-     * This information is private to the scsi mid-layer.  Wrapping it in a
-     * struct private is a way of marking it in a sort of C++ type of way.
-     */
-    struct scsi_device * next;      /* Used for linked list */
-    struct scsi_device * prev;      /* Used for linked list */
-    wait_queue_head_t device_wait;/* Used to wait if
-                                                      device is busy */
-    struct Scsi_Host   * host;
-    volatile unsigned short device_busy;   /* commands actually active on low-level */
-    void              (* scsi_request_fn)(void);  /* Used to jumpstart things after an 
-                                     * ioctl */
-    Scsi_Cmnd          * device_queue;    /* queue of SCSI Command structures */
+	/*
+	 * This information is private to the scsi mid-layer.  Wrapping it in a
+	 * struct private is a way of marking it in a sort of C++ type of way.
+	 */
+	struct scsi_device *next;	/* Used for linked list */
+	struct scsi_device *prev;	/* Used for linked list */
+	wait_queue_head_t device_wait;	/* Used to wait if
+					   device is busy */
+	struct Scsi_Host *host;
+	volatile unsigned short device_busy;	/* commands actually active on low-level */
+	void (*scsi_request_fn) (void);		/* Used to jumpstart things after an 
+						   * ioctl */
+	Scsi_Cmnd *device_queue;	/* queue of SCSI Command structures */
 
 /* public: */
-    unsigned char id, lun, channel;
+	unsigned char id, lun, channel;
 
-    unsigned int manufacturer;      /* Manufacturer of device, for using 
-				     * vendor-specific cmd's */
-    int attached;                   /* # of high level drivers attached to 
-				     * this */
-    int access_count;               /* Count of open channels/mounts */
-
-    void *hostdata;                 /* available to low-level driver */
-    char type;
-    char scsi_level;
-    char vendor[8], model[16], rev[4];
-    unsigned char current_tag;      /* current tag */
-    unsigned char sync_min_period;  /* Not less than this period */
-    unsigned char sync_max_offset;  /* Not greater than this offset */
-    unsigned char queue_depth;	    /* How deep a queue to use */
-
-    unsigned online:1;
-    unsigned writeable:1;
-    unsigned removable:1; 
-    unsigned random:1;
-    unsigned has_cmdblocks:1;
-    unsigned changed:1;             /* Data invalid due to media change */
-    unsigned busy:1;                /* Used to prevent races */
-    unsigned lockable:1;            /* Able to prevent media removal */
-    unsigned borken:1;              /* Tell the Seagate driver to be 
-				     * painfully slow on this device */ 
-    unsigned tagged_supported:1;    /* Supports SCSI-II tagged queuing */
-    unsigned tagged_queue:1;        /* SCSI-II tagged queuing enabled */
-    unsigned disconnect:1;          /* can disconnect */
-    unsigned soft_reset:1;          /* Uses soft reset option */
-    unsigned sync:1;                /* Negotiate for sync transfers */
-    unsigned wide:1;                /* Negotiate for WIDE transfers */
-    unsigned single_lun:1;          /* Indicates we should only allow I/O to
-                                     * one of the luns for the device at a 
-                                     * time. */
-    unsigned was_reset:1;           /* There was a bus reset on the bus for 
-                                     * this device */
-    unsigned expecting_cc_ua:1;     /* Expecting a CHECK_CONDITION/UNIT_ATTN
-                                     * because we did a bus reset. */
-    unsigned device_blocked:1;      /* Device returned QUEUE_FULL. */
+	unsigned int manufacturer;	/* Manufacturer of device, for using 
+					 * vendor-specific cmd's */
+	int attached;		/* # of high level drivers attached to 
+				 * this */
+	int access_count;	/* Count of open channels/mounts */
+
+	void *hostdata;		/* available to low-level driver */
+	char type;
+	char scsi_level;
+	char vendor[8], model[16], rev[4];
+	unsigned char current_tag;	/* current tag */
+	unsigned char sync_min_period;	/* Not less than this period */
+	unsigned char sync_max_offset;	/* Not greater than this offset */
+	unsigned char queue_depth;	/* How deep a queue to use */
+
+	unsigned online:1;
+	unsigned writeable:1;
+	unsigned removable:1;
+	unsigned random:1;
+	unsigned has_cmdblocks:1;
+	unsigned changed:1;	/* Data invalid due to media change */
+	unsigned busy:1;	/* Used to prevent races */
+	unsigned lockable:1;	/* Able to prevent media removal */
+	unsigned borken:1;	/* Tell the Seagate driver to be 
+				 * painfully slow on this device */
+	unsigned tagged_supported:1;	/* Supports SCSI-II tagged queuing */
+	unsigned tagged_queue:1;	/* SCSI-II tagged queuing enabled */
+	unsigned disconnect:1;	/* can disconnect */
+	unsigned soft_reset:1;	/* Uses soft reset option */
+	unsigned sync:1;	/* Negotiate for sync transfers */
+	unsigned wide:1;	/* Negotiate for WIDE transfers */
+	unsigned single_lun:1;	/* Indicates we should only allow I/O to
+				 * one of the luns for the device at a 
+				 * time. */
+	unsigned was_reset:1;	/* There was a bus reset on the bus for 
+				 * this device */
+	unsigned expecting_cc_ua:1;	/* Expecting a CHECK_CONDITION/UNIT_ATTN
+					 * because we did a bus reset. */
+	unsigned device_blocked:1;	/* Device returned QUEUE_FULL. */
 };
 
 
@@ -476,147 +476,147 @@
  * with low level drivers that support multiple outstanding commands.
  */
 typedef struct scsi_pointer {
-    char * ptr;                     /* data pointer */
-    int this_residual;              /* left in this buffer */
-    struct scatterlist *buffer;     /* which buffer */
-    int buffers_residual;           /* how many buffers left */
-    
-    volatile int Status;
-    volatile int Message;
-    volatile int have_data_in;
-    volatile int sent_command;
-    volatile int phase;
+	char *ptr;		/* data pointer */
+	int this_residual;	/* left in this buffer */
+	struct scatterlist *buffer;	/* which buffer */
+	int buffers_residual;	/* how many buffers left */
+
+	volatile int Status;
+	volatile int Message;
+	volatile int have_data_in;
+	volatile int sent_command;
+	volatile int phase;
 } Scsi_Pointer;
 
 
 struct scsi_cmnd {
 /* private: */
-    /*
-     * This information is private to the scsi mid-layer.  Wrapping it in a
-     * struct private is a way of marking it in a sort of C++ type of way.
-     */
-    struct Scsi_Host * host;
-    unsigned short     state;
-    unsigned short     owner;
-    Scsi_Device      * device;
-    struct scsi_cmnd * next;
-    struct scsi_cmnd * reset_chain;
-    
-    int                 eh_state; /* Used for state tracking in error handlr */
-    void               (*done)(struct scsi_cmnd *);  /* Mid-level done function */
-    /*
-      A SCSI Command is assigned a nonzero serial_number when internal_cmnd
-      passes it to the driver's queue command function.  The serial_number
-      is cleared when scsi_done is entered indicating that the command has
-      been completed.  If a timeout occurs, the serial number at the moment
-      of timeout is copied into serial_number_at_timeout.  By subsequently
-      comparing the serial_number and serial_number_at_timeout fields
-      during abort or reset processing, we can detect whether the command
-      has already completed.  This also detects cases where the command has
-      completed and the SCSI Command structure has already being reused
-      for another command, so that we can avoid incorrectly aborting or
-      resetting the new command.
-      */
-    
-    unsigned long      serial_number;
-    unsigned long      serial_number_at_timeout;
-    
-    int                retries;
-    int                allowed;
-    int                timeout_per_command;
-    int                timeout_total;
-    int                timeout;
-    
-    /*
-     * We handle the timeout differently if it happens when a reset, 
-     * abort, etc are in process. 
-     */
-    unsigned volatile char internal_timeout;
-    struct scsi_cmnd  * bh_next;  /* To enumerate the commands waiting 
-                                     to be processed. */
-    
+	/*
+	 * This information is private to the scsi mid-layer.  Wrapping it in a
+	 * struct private is a way of marking it in a sort of C++ type of way.
+	 */
+	struct Scsi_Host *host;
+	unsigned short state;
+	unsigned short owner;
+	Scsi_Device *device;
+	struct scsi_cmnd *next;
+	struct scsi_cmnd *reset_chain;
+
+	int eh_state;		/* Used for state tracking in error handlr */
+	void (*done) (struct scsi_cmnd *);	/* Mid-level done function */
+	/*
+	   A SCSI Command is assigned a nonzero serial_number when internal_cmnd
+	   passes it to the driver's queue command function.  The serial_number
+	   is cleared when scsi_done is entered indicating that the command has
+	   been completed.  If a timeout occurs, the serial number at the moment
+	   of timeout is copied into serial_number_at_timeout.  By subsequently
+	   comparing the serial_number and serial_number_at_timeout fields
+	   during abort or reset processing, we can detect whether the command
+	   has already completed.  This also detects cases where the command has
+	   completed and the SCSI Command structure has already being reused
+	   for another command, so that we can avoid incorrectly aborting or
+	   resetting the new command.
+	 */
+
+	unsigned long serial_number;
+	unsigned long serial_number_at_timeout;
+
+	int retries;
+	int allowed;
+	int timeout_per_command;
+	int timeout_total;
+	int timeout;
+
+	/*
+	 * We handle the timeout differently if it happens when a reset, 
+	 * abort, etc are in process. 
+	 */
+	unsigned volatile char internal_timeout;
+	struct scsi_cmnd *bh_next;	/* To enumerate the commands waiting 
+					   to be processed. */
+
 /* public: */
 
-    unsigned char      target;
-    unsigned char      lun;
-    unsigned char      channel;
-    unsigned char      cmd_len;
-    unsigned char      old_cmd_len;
-
-    /* These elements define the operation we are about to perform */
-    unsigned char      cmnd[12];
-    unsigned           request_bufflen;	/* Actual request size */
-    
-    struct timer_list  eh_timeout;         /* Used to time out the command. */
-    void             * request_buffer;	/* Actual requested buffer */
-    
-    /* These elements define the operation we ultimately want to perform */
-    unsigned char      data_cmnd[12];
-    unsigned short     old_use_sg;	/* We save  use_sg here when requesting
-                                         * sense info */
-    unsigned short     use_sg;          /* Number of pieces of scatter-gather */
-    unsigned short     sglist_len;	/* size of malloc'd scatter-gather list */
-    unsigned short     abort_reason;    /* If the mid-level code requests an
-                                         * abort, this is the reason. */
-    unsigned           bufflen;		/* Size of data buffer */
-    void             * buffer;		/* Data buffer */
-    
-    unsigned           underflow;	/* Return error if less than
-                                           this amount is transfered */
-    
-    unsigned           transfersize;	/* How much we are guaranteed to
-                                           transfer with each SCSI transfer
-                                           (ie, between disconnect / 
-                                           reconnects.	 Probably == sector
-                                           size */
-    
-    
-    struct request     request;           /* A copy of the command we are
-                                             working on */
-
-    unsigned char      sense_buffer[16];  /* Sense for this command, 
-                                             needed */
-    
-    unsigned           flags;
-    
-    /*
-     * These two flags are used to track commands that are in the
-     * mid-level queue.  The idea is that a command can be there for
-     * one of two reasons - either the host is busy or the device is
-     * busy.  Thus when a command on the host finishes, we only try
-     * and requeue commands that we might expect to be queueable.
-     */
-    unsigned           host_wait:1;
-    unsigned           device_wait:1;
-
-    /* These variables are for the cdrom only. Once we have variable size 
-     * buffers in the buffer cache, they will go away. */
-    int                this_count; 
-    /* End of special cdrom variables */
-    
-    /* Low-level done function - can be used by low-level driver to point
-     *	to completion function.	 Not used by mid/upper level code. */
-    void               (*scsi_done)(struct scsi_cmnd *);  
-    
-    /*
-     * The following fields can be written to by the host specific code. 
-     * Everything else should be left alone. 
-     */
-    
-    Scsi_Pointer       SCp;	   /* Scratchpad used by some host adapters */
-    
-    unsigned char    * host_scribble; /* The host adapter is allowed to
-				    * call scsi_malloc and get some memory
-				    * and hang it here.	 The host adapter
-				    * is also expected to call scsi_free
-				    * to release this memory.  (The memory
-				    * obtained by scsi_malloc is guaranteed
-				    * to be at an address < 16Mb). */
-    
-    int                result;	   /* Status code from lower level driver */
-    
-    unsigned char      tag;	   /* SCSI-II queued command tag */
-    unsigned long      pid;	   /* Process ID, starts at 0 */
+	unsigned char target;
+	unsigned char lun;
+	unsigned char channel;
+	unsigned char cmd_len;
+	unsigned char old_cmd_len;
+
+	/* These elements define the operation we are about to perform */
+	unsigned char cmnd[12];
+	unsigned request_bufflen;	/* Actual request size */
+
+	struct timer_list eh_timeout;	/* Used to time out the command. */
+	void *request_buffer;	/* Actual requested buffer */
+
+	/* These elements define the operation we ultimately want to perform */
+	unsigned char data_cmnd[12];
+	unsigned short old_use_sg;	/* We save  use_sg here when requesting
+					 * sense info */
+	unsigned short use_sg;	/* Number of pieces of scatter-gather */
+	unsigned short sglist_len;	/* size of malloc'd scatter-gather list */
+	unsigned short abort_reason;	/* If the mid-level code requests an
+					 * abort, this is the reason. */
+	unsigned bufflen;	/* Size of data buffer */
+	void *buffer;		/* Data buffer */
+
+	unsigned underflow;	/* Return error if less than
+				   this amount is transfered */
+
+	unsigned transfersize;	/* How much we are guaranteed to
+				   transfer with each SCSI transfer
+				   (ie, between disconnect / 
+				   reconnects.   Probably == sector
+				   size */
+
+
+	struct request request;	/* A copy of the command we are
+				   working on */
+
+	unsigned char sense_buffer[16];		/* Sense for this command, 
+						   needed */
+
+	unsigned flags;
+
+	/*
+	 * These two flags are used to track commands that are in the
+	 * mid-level queue.  The idea is that a command can be there for
+	 * one of two reasons - either the host is busy or the device is
+	 * busy.  Thus when a command on the host finishes, we only try
+	 * and requeue commands that we might expect to be queueable.
+	 */
+	unsigned host_wait:1;
+	unsigned device_wait:1;
+
+	/* These variables are for the cdrom only. Once we have variable size 
+	 * buffers in the buffer cache, they will go away. */
+	int this_count;
+	/* End of special cdrom variables */
+
+	/* Low-level done function - can be used by low-level driver to point
+	 *        to completion function.  Not used by mid/upper level code. */
+	void (*scsi_done) (struct scsi_cmnd *);
+
+	/*
+	 * The following fields can be written to by the host specific code. 
+	 * Everything else should be left alone. 
+	 */
+
+	Scsi_Pointer SCp;	/* Scratchpad used by some host adapters */
+
+	unsigned char *host_scribble;	/* The host adapter is allowed to
+					   * call scsi_malloc and get some memory
+					   * and hang it here.     The host adapter
+					   * is also expected to call scsi_free
+					   * to release this memory.  (The memory
+					   * obtained by scsi_malloc is guaranteed
+					   * to be at an address < 16Mb). */
+
+	int result;		/* Status code from lower level driver */
+
+	unsigned char tag;	/* SCSI-II queued command tag */
+	unsigned long pid;	/* Process ID, starts at 0 */
 };
 
 
@@ -627,63 +627,61 @@
 #define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
 
 extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
-extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device);
+extern int scsi_mlqueue_finish(struct Scsi_Host *host, Scsi_Device * device);
 
 
 #if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
 #include "hosts.h"
 
-static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
+static Scsi_Cmnd *end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
 {
-    struct request * req;
-    struct buffer_head * bh;
-    
-    req = &SCpnt->request;
-    req->errors = 0;
-    if (!uptodate) {
-	printk(DEVICE_NAME " I/O error: dev %s, sector %lu\n",
-	       kdevname(req->rq_dev), req->sector);
-    }
-    
-    do {
-	if ((bh = req->bh) != NULL) {
-	    req->bh = bh->b_reqnext;
-	    req->nr_sectors -= bh->b_size >> 9;
-	    req->sector += bh->b_size >> 9;
-	    bh->b_reqnext = NULL;
-	    bh->b_end_io(bh, uptodate);
-	    sectors -= bh->b_size >> 9;
-	    if ((bh = req->bh) != NULL) {
-		req->current_nr_sectors = bh->b_size >> 9;
-		if (req->nr_sectors < req->current_nr_sectors) {
-		    req->nr_sectors = req->current_nr_sectors;
-		    printk("end_scsi_request: buffer-list destroyed\n");
+	struct request *req;
+	struct buffer_head *bh;
+
+	req = &SCpnt->request;
+	req->errors = 0;
+	if (!uptodate) {
+		printk(DEVICE_NAME " I/O error: dev %s, sector %lu\n",
+		       kdevname(req->rq_dev), req->sector);
+	}
+	do {
+		if ((bh = req->bh) != NULL) {
+			req->bh = bh->b_reqnext;
+			req->nr_sectors -= bh->b_size >> 9;
+			req->sector += bh->b_size >> 9;
+			bh->b_reqnext = NULL;
+			bh->b_end_io(bh, uptodate);
+			sectors -= bh->b_size >> 9;
+			if ((bh = req->bh) != NULL) {
+				req->current_nr_sectors = bh->b_size >> 9;
+				if (req->nr_sectors < req->current_nr_sectors) {
+					req->nr_sectors = req->current_nr_sectors;
+					printk("end_scsi_request: buffer-list destroyed\n");
+				}
+			}
 		}
-	    }
+	} while (sectors && bh);
+	if (req->bh) {
+		req->buffer = bh->b_data;
+		return SCpnt;
+	}
+	DEVICE_OFF(req->rq_dev);
+	if (req->sem != NULL) {
+		up(req->sem);
+	}
+	add_blkdev_randomness(MAJOR(req->rq_dev));
+
+	if (SCpnt->host->block) {
+		struct Scsi_Host *next;
+
+		for (next = SCpnt->host->block; next != SCpnt->host;
+		     next = next->block)
+			wake_up(&next->host_wait);
 	}
-    } while(sectors && bh);
-    if (req->bh){
-	req->buffer = bh->b_data;
-	return SCpnt;
-    }
-    DEVICE_OFF(req->rq_dev);
-    if (req->sem != NULL) {
-	up(req->sem);
-    }
-    add_blkdev_randomness(MAJOR(req->rq_dev));
-    
-    if (SCpnt->host->block) {
-	struct Scsi_Host * next;
-	
-	for (next = SCpnt->host->block; next != SCpnt->host;
-	     next = next->block)
-	    wake_up(&next->host_wait);
-    }
-    
-    wake_up(&wait_for_request);
-    wake_up(&SCpnt->device->device_wait);
-    scsi_release_command(SCpnt);
-    return NULL;
+	wake_up(&wait_for_request);
+	wake_up(&SCpnt->device->device_wait);
+	scsi_release_command(SCpnt);
+	return NULL;
 }
 
 
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c
--- v2.3.16/linux/drivers/scsi/scsi_debug.c	Mon Jul  5 20:35:18 1999
+++ linux/drivers/scsi/scsi_debug.c	Sat Sep  4 10:48:46 1999
@@ -30,9 +30,10 @@
 
 #include<linux/stat.h>
 
-struct proc_dir_entry proc_scsi_scsi_debug = {
-    PROC_SCSI_SCSI_DEBUG, 10, "scsi_debug",
-    S_IFDIR | S_IRUGO | S_IXUGO, 2
+struct proc_dir_entry proc_scsi_scsi_debug =
+{
+	PROC_SCSI_SCSI_DEBUG, 10, "scsi_debug",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
 
@@ -55,7 +56,7 @@
 #define CLEAR
 
 /* Number of real scsi disks that will be detected ahead of time */
-static int NR_REAL=-1;
+static int NR_REAL = -1;
 
 #define NR_BLK_DEV  12
 #ifndef MAJOR_NR
@@ -67,7 +68,8 @@
 #define DISK_SPEED     10
 #define CAPACITY (0x80000)
 
-static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
+static int starts[] =
+{N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
 static int npart = 0;
 
 #include "scsi_debug.h"
@@ -78,8 +80,8 @@
 #endif
 
 #ifdef SPEEDY
-#define VERIFY1_DEBUG(RW) 
-#define VERIFY_DEBUG(RW) 
+#define VERIFY1_DEBUG(RW)
+#define VERIFY_DEBUG(RW)
 #else
 
 #define VERIFY1_DEBUG(RW)                           \
@@ -115,15 +117,15 @@
     };
 #endif
 
-typedef void (*done_fct_t)(Scsi_Cmnd *);
+typedef void (*done_fct_t) (Scsi_Cmnd *);
 
-static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL, };
+static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL,};
 
 static void scsi_debug_intr_handle(unsigned long);
 
 static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
 
-Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
+Scsi_Cmnd *SCint[SCSI_DEBUG_MAILBOXES]  = {NULL,};
 static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
 
 /*
@@ -133,379 +135,384 @@
 
 static char sense_buffer[128] = {0,};
 
-static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
-    int i;
+static void scsi_dump(Scsi_Cmnd * SCpnt, int flag)
+{
+	int i;
 #if 0
-    unsigned char * pnt;
+	unsigned char *pnt;
 #endif
-    unsigned int * lpnt;
-    struct scatterlist * sgpnt = NULL;
-    printk("use_sg: %d",SCpnt->use_sg);
-    if (SCpnt->use_sg){
-	sgpnt = (struct scatterlist *) SCpnt->buffer;
-	for(i=0; i<SCpnt->use_sg; i++) {
-	    lpnt = (int *) sgpnt[i].alt_address;
-	    printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-	    if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+	unsigned int *lpnt;
+	struct scatterlist *sgpnt = NULL;
+	printk("use_sg: %d", SCpnt->use_sg);
+	if (SCpnt->use_sg) {
+		sgpnt = (struct scatterlist *) SCpnt->buffer;
+		for (i = 0; i < SCpnt->use_sg; i++) {
+			lpnt = (int *) sgpnt[i].alt_address;
+			printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+			if (lpnt)
+				printk(" (Alt %x) ", lpnt[15]);
+		};
+	} else {
+		printk("nosg: %p %p %d\n", SCpnt->request.buffer, SCpnt->buffer,
+		       SCpnt->bufflen);
+		lpnt = (int *) SCpnt->request.buffer;
+		if (lpnt)
+			printk(" (Alt %x) ", lpnt[15]);
+	};
+	lpnt = (unsigned int *) SCpnt;
+	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
+		if ((i & 7) == 0)
+			printk("\n");
+		printk("%x ", *lpnt++);
+	};
+	printk("\n");
+	if (flag == 0)
+		return;
+	lpnt = (unsigned int *) sgpnt[0].alt_address;
+	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
+		if ((i & 7) == 0)
+			printk("\n");
+		printk("%x ", *lpnt++);
 	};
-    } else {
-	printk("nosg: %p %p %d\n",SCpnt->request.buffer, SCpnt->buffer,
-	       SCpnt->bufflen);
-	lpnt = (int *) SCpnt->request.buffer;
-	if (lpnt) printk(" (Alt %x) ",lpnt[15]);
-    };
-    lpnt = (unsigned int *) SCpnt;
-    for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
-	if ((i & 7) == 0) printk("\n");
-	printk("%x ",*lpnt++);
-    };
-    printk("\n");
-    if (flag == 0) return;
-    lpnt = (unsigned int *) sgpnt[0].alt_address;
-    for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
-	if ((i & 7) == 0) printk("\n");
-	printk("%x ",*lpnt++);
-    };
 #if 0
-    printk("\n");
-    lpnt = (unsigned int *) sgpnt[0].address;
-    for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
-	if ((i & 7) == 0) printk("\n");
-	printk("%x ",*lpnt++);
-    };
-    printk("\n");
+	printk("\n");
+	lpnt = (unsigned int *) sgpnt[0].address;
+	for (i = 0; i < sizeof(Scsi_Cmnd) / 4 + 1; i++) {
+		if ((i & 7) == 0)
+			printk("\n");
+		printk("%x ", *lpnt++);
+	};
+	printk("\n");
 #endif
-    printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
+	printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
 }
 
-int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
-    unchar *cmd = (unchar *) SCpnt->cmnd;
-    struct partition * p;
-    int block;
-    struct buffer_head * bh = NULL;
-    unsigned char * buff;
-    int nbytes, sgcount;
-    int scsi_debug_errsts;
-    struct scatterlist * sgpnt;
-    int target = SCpnt->target;
-    int bufflen = SCpnt->request_bufflen;
-    unsigned long flags;
-    int i;
-    sgcount = 0;
-    sgpnt = NULL;
-    
-    /*
-     * If we are being notified of the mid-level reposessing a command due to timeout,
-     * just return.
-     */
-    if( done == NULL )
-    {
-        return 0;
-    }
-
-    DEB(if (target >= NR_FAKE_DISKS) 
-        { 
-            SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;
-        });
-    
-    buff = (unsigned char *) SCpnt->request_buffer;
-    
-    if(target>=NR_FAKE_DISKS || SCpnt->lun != 0) 
-    {
-	SCpnt->result =  DID_NO_CONNECT << 16;
-	done(SCpnt);
-	return 0;
-    }
-    
-    if( SCrst[target] != 0 && !scsi_debug_lockup )
-    {
-        SCrst[target] = 0;
-        memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-        SCpnt->sense_buffer[0] = 0x70;
-        SCpnt->sense_buffer[2] = UNIT_ATTENTION;
-	SCpnt->result = (CHECK_CONDITION << 1);
-	done(SCpnt);         
-    }
-    switch(*cmd){
-    case REQUEST_SENSE:
-	SCSI_LOG_LLQUEUE(3,printk("Request sense...\n"));
+	unchar *cmd = (unchar *) SCpnt->cmnd;
+	struct partition *p;
+	int block;
+	struct buffer_head *bh = NULL;
+	unsigned char *buff;
+	int nbytes, sgcount;
+	int scsi_debug_errsts;
+	struct scatterlist *sgpnt;
+	int target = SCpnt->target;
+	int bufflen = SCpnt->request_bufflen;
+	unsigned long flags;
+	int i;
+	sgcount = 0;
+	sgpnt = NULL;
+
+	/*
+	 * If we are being notified of the mid-level reposessing a command due to timeout,
+	 * just return.
+	 */
+	if (done == NULL) {
+		return 0;
+	}
+	DEB(if (target >= NR_FAKE_DISKS) {
+	    SCpnt->result = DID_TIME_OUT << 16; done(SCpnt); return 0;
+	    }
+	);
+
+	buff = (unsigned char *) SCpnt->request_buffer;
+
+	if (target >= NR_FAKE_DISKS || SCpnt->lun != 0) {
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	}
+	if (SCrst[target] != 0 && !scsi_debug_lockup) {
+		SCrst[target] = 0;
+		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+		SCpnt->sense_buffer[0] = 0x70;
+		SCpnt->sense_buffer[2] = UNIT_ATTENTION;
+		SCpnt->result = (CHECK_CONDITION << 1);
+		done(SCpnt);
+	}
+	switch (*cmd) {
+	case REQUEST_SENSE:
+		SCSI_LOG_LLQUEUE(3, printk("Request sense...\n"));
 #ifndef DEBUG
-	{ 
-	    int i;
-	    printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
-	    for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
-	    printk("\n");
-	};
+		{
+			int i;
+			printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
+			for (i = 0; i < 12; i++)
+				printk("%d ", sense_buffer[i]);
+			printk("\n");
+		};
 #endif
-	memset(buff, 0, bufflen);
-	memcpy(buff, sense_buffer, bufflen);
-	memset(sense_buffer, 0, sizeof(sense_buffer));
-	SCpnt->result = 0;
-	done(SCpnt); 
-	return 0;
-    case ALLOW_MEDIUM_REMOVAL:
-	if(cmd[4]) 
-        {
-            SCSI_LOG_LLQUEUE(2,printk("Medium removal inhibited..."));
-        }
-	else
-        {
-            SCSI_LOG_LLQUEUE(2,printk("Medium removal enabled..."));
-        }
-	scsi_debug_errsts = 0;
-	break;
-    case INQUIRY:
-	SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen));
-	memset(buff, 0, bufflen);
-	buff[0] = TYPE_DISK;
-	buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;  /* Removable disk */
-	buff[2] = 1;
-	buff[4] = 33 - 5;
-	memcpy(&buff[8],"Foo Inc",7);
-	memcpy(&buff[16],"XYZZY",5);
-	memcpy(&buff[32],"1",1);
-	scsi_debug_errsts = 0;
-	break;
-    case TEST_UNIT_READY:
-	SCSI_LOG_LLQUEUE(3,printk("Test unit ready(%p %d)\n", buff, bufflen));
-	if (buff)
-	    memset(buff, 0, bufflen);
-	scsi_debug_errsts = 0;
-	break;
-    case READ_CAPACITY:
-	SCSI_LOG_LLQUEUE(3,printk("Read Capacity\n"));
-	if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
-	memset(buff, 0, bufflen);
-	buff[0] = (CAPACITY >> 24);
-	buff[1] = (CAPACITY >> 16) & 0xff;
-	buff[2] = (CAPACITY >> 8) & 0xff;
-	buff[3] = CAPACITY & 0xff;
-	buff[6] = 2; /* 512 byte sectors */
-	scsi_debug_errsts = 0;
-	break;
-    case READ_10:
-    case READ_6:
+		memset(buff, 0, bufflen);
+		memcpy(buff, sense_buffer, bufflen);
+		memset(sense_buffer, 0, sizeof(sense_buffer));
+		SCpnt->result = 0;
+		done(SCpnt);
+		return 0;
+	case ALLOW_MEDIUM_REMOVAL:
+		if (cmd[4]) {
+			SCSI_LOG_LLQUEUE(2, printk("Medium removal inhibited..."));
+		} else {
+			SCSI_LOG_LLQUEUE(2, printk("Medium removal enabled..."));
+		}
+		scsi_debug_errsts = 0;
+		break;
+	case INQUIRY:
+		SCSI_LOG_LLQUEUE(3, printk("Inquiry...(%p %d)\n", buff, bufflen));
+		memset(buff, 0, bufflen);
+		buff[0] = TYPE_DISK;
+		buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
+		buff[2] = 1;
+		buff[4] = 33 - 5;
+		memcpy(&buff[8], "Foo Inc", 7);
+		memcpy(&buff[16], "XYZZY", 5);
+		memcpy(&buff[32], "1", 1);
+		scsi_debug_errsts = 0;
+		break;
+	case TEST_UNIT_READY:
+		SCSI_LOG_LLQUEUE(3, printk("Test unit ready(%p %d)\n", buff, bufflen));
+		if (buff)
+			memset(buff, 0, bufflen);
+		scsi_debug_errsts = 0;
+		break;
+	case READ_CAPACITY:
+		SCSI_LOG_LLQUEUE(3, printk("Read Capacity\n"));
+		if (NR_REAL < 0)
+			NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
+		memset(buff, 0, bufflen);
+		buff[0] = (CAPACITY >> 24);
+		buff[1] = (CAPACITY >> 16) & 0xff;
+		buff[2] = (CAPACITY >> 8) & 0xff;
+		buff[3] = CAPACITY & 0xff;
+		buff[6] = 2;	/* 512 byte sectors */
+		scsi_debug_errsts = 0;
+		break;
+	case READ_10:
+	case READ_6:
 #ifdef DEBUG
-	printk("Read...");
+		printk("Read...");
 #endif
-	if ((*cmd) == READ_10)
-	    block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
-	else 
-	    block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-	VERIFY_DEBUG(READ);
+		if ((*cmd) == READ_10)
+			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
+		else
+			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+		VERIFY_DEBUG(READ);
 #if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
-    {
-	int delay = SCSI_SETUP_LATENCY;
-	
-	delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
-	if(delay) usleep(delay);
-    };
+		{
+			int delay = SCSI_SETUP_LATENCY;
+
+			delay += SCpnt->request.nr_sectors * SCSI_DATARATE;
+			if (delay)
+				usleep(delay);
+		};
 #endif
-	
+
 #ifdef DEBUG
-	printk("(r%d)",SCpnt->request.nr_sectors);
+		printk("(r%d)", SCpnt->request.nr_sectors);
 #endif
-	nbytes = bufflen;
-	if(SCpnt->use_sg){
-	    sgcount = 0;
-	    sgpnt = (struct scatterlist *) buff;
-	    buff = sgpnt[sgcount].address;
-	    bufflen = sgpnt[sgcount].length;
-	    bh = SCpnt->request.bh;
-	};
-	scsi_debug_errsts = 0;
-	do{
-	    VERIFY1_DEBUG(READ);
-	    /* For the speedy test, we do not even want to fill the buffer with anything */
-#ifdef CLEAR
-	    memset(buff, 0, bufflen);
-#endif
-	    /* If this is block 0, then we want to read the partition table for this
-	     * device.  Let's make one up */
-	    if(block == 0) {
-	    	int i;
-                memset(buff, 0, bufflen);
-		*((unsigned short *) (buff+510)) = 0xAA55;
-		p = (struct partition* ) (buff + 0x1be);
-		i = 0;
-		while(starts[i+1]){
-		    p->start_sect = starts[i];
-		    p->nr_sects = starts[i+1] - starts [i];
-		    p->sys_ind = 0x81;  /* Linux partition */
-                    p->head       = (i == 0 ? 1 : 0);
-                    p->sector     = 1;
-                    p->cyl        = starts[i] / N_HEAD / N_SECTOR;
-                    p->end_head   = N_HEAD - 1;
-                    p->end_sector = N_SECTOR;
-                    p->end_cyl    = starts[i + 1] / N_HEAD / N_SECTOR;
-		    p++;
-		    i++;
+		nbytes = bufflen;
+		if (SCpnt->use_sg) {
+			sgcount = 0;
+			sgpnt = (struct scatterlist *) buff;
+			buff = sgpnt[sgcount].address;
+			bufflen = sgpnt[sgcount].length;
+			bh = SCpnt->request.bh;
 		};
-		if (!npart) npart = i;
 		scsi_debug_errsts = 0;
-		break;
-	    };
+		do {
+			VERIFY1_DEBUG(READ);
+			/* For the speedy test, we do not even want to fill the buffer with anything */
+#ifdef CLEAR
+			memset(buff, 0, bufflen);
+#endif
+			/* If this is block 0, then we want to read the partition table for this
+			 * device.  Let's make one up */
+			if (block == 0) {
+				int i;
+				memset(buff, 0, bufflen);
+				*((unsigned short *) (buff + 510)) = 0xAA55;
+				p = (struct partition *) (buff + 0x1be);
+				i = 0;
+				while (starts[i + 1]) {
+					p->start_sect = starts[i];
+					p->nr_sects = starts[i + 1] - starts[i];
+					p->sys_ind = 0x81;	/* Linux partition */
+					p->head = (i == 0 ? 1 : 0);
+					p->sector = 1;
+					p->cyl = starts[i] / N_HEAD / N_SECTOR;
+					p->end_head = N_HEAD - 1;
+					p->end_sector = N_SECTOR;
+					p->end_cyl = starts[i + 1] / N_HEAD / N_SECTOR;
+					p++;
+					i++;
+				};
+				if (!npart)
+					npart = i;
+				scsi_debug_errsts = 0;
+				break;
+			};
 #ifdef DEBUG
-	    if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
-				      SCpnt->request.current_nr_sectors);
+			if (SCpnt->use_sg)
+				printk("Block %x (%d %d)\n", block, SCpnt->request.nr_sectors,
+				       SCpnt->request.current_nr_sectors);
 #endif
-	    
+
 #if 0
-	    /* Simulate a disk change */
-	    if(block == 0xfff0) {
-		sense_buffer[0] = 0x70;
-		sense_buffer[2] = UNIT_ATTENTION;
-		starts[0] += 10;
-		starts[1] += 10;
-		starts[2] += 10;
-		
+			/* Simulate a disk change */
+			if (block == 0xfff0) {
+				sense_buffer[0] = 0x70;
+				sense_buffer[2] = UNIT_ATTENTION;
+				starts[0] += 10;
+				starts[1] += 10;
+				starts[2] += 10;
+
 #ifdef DEBUG
-		{ 
-		    int i;
-		    printk("scsi_debug: Filling sense buffer:");
-		    for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
-		    printk("\n");
-		};
-#endif
-		scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
-		break;
-	    } /* End phony disk change code */
-#endif
-	    
+				{
+					int i;
+					printk("scsi_debug: Filling sense buffer:");
+					for (i = 0; i < 12; i++)
+						printk("%d ", sense_buffer[i]);
+					printk("\n");
+				};
+#endif
+				scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+				break;
+			}	/* End phony disk change code */
+#
+
 #ifdef CLEAR
-	    memcpy(buff, &target, sizeof(target));
-	    memcpy(buff+sizeof(target), cmd, 24);
-	    memcpy(buff+60, &block, sizeof(block));
-	    memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
+			memcpy(buff, &target, sizeof(target));
+			memcpy(buff + sizeof(target), cmd, 24);
+			memcpy(buff + 60, &block, sizeof(block));
+			memcpy(buff + 64, SCpnt, sizeof(Scsi_Cmnd));
 #endif
-	    nbytes -= bufflen;
-	    if(SCpnt->use_sg){
+			nbytes -= bufflen;
+			if (SCpnt->use_sg) {
 #ifdef CLEAR
-		memcpy(buff+128, bh, sizeof(struct buffer_head));
+				memcpy(buff + 128, bh, sizeof(struct buffer_head));
 #endif
-		block += bufflen >> 9;
-		bh = bh->b_reqnext;
-		sgcount++;
-		if (nbytes) {
-		    if(!bh) panic("Too few blocks for linked request.");
-		    buff = sgpnt[sgcount].address;
-		    bufflen = sgpnt[sgcount].length;
-		};
-	    }
-	} while(nbytes);
-	
-	SCpnt->result = 0;
-	(done)(SCpnt);
-	return 0;
-	
-	if (SCpnt->use_sg && !scsi_debug_errsts)
-	    if(bh) scsi_dump(SCpnt, 0);
-	break;
-    case WRITE_10:
-    case WRITE_6:
+				block += bufflen >> 9;
+				bh = bh->b_reqnext;
+				sgcount++;
+				if (nbytes) {
+					if (!bh)
+						panic("Too few blocks for linked request.");
+					buff = sgpnt[sgcount].address;
+					bufflen = sgpnt[sgcount].length;
+				};
+			}
+		} while (nbytes);
+
+		SCpnt->result = 0;
+		(done) (SCpnt);
+		return 0;
+
+		if (SCpnt->use_sg && !scsi_debug_errsts)
+			if (bh)
+				scsi_dump(SCpnt, 0);
+		break;
+	case WRITE_10:
+	case WRITE_6:
 #ifdef DEBUG
-	printk("Write\n");
+		printk("Write\n");
 #endif
-	if ((*cmd) == WRITE_10)
-	    block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); 
-	else 
-	    block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
-	VERIFY_DEBUG(WRITE);
-	/*      printk("(w%d)",SCpnt->request.nr_sectors); */
-	if (SCpnt->use_sg){
-	    if ((bufflen >> 9) != SCpnt->request.nr_sectors)
-		panic ("Trying to write wrong number of blocks\n");
-	    sgpnt = (struct scatterlist *) buff;
-	    buff = sgpnt[sgcount].address;
-	};
+		if ((*cmd) == WRITE_10)
+			block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
+		else
+			block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+		VERIFY_DEBUG(WRITE);
+		/*      printk("(w%d)",SCpnt->request.nr_sectors); */
+		if (SCpnt->use_sg) {
+			if ((bufflen >> 9) != SCpnt->request.nr_sectors)
+				panic("Trying to write wrong number of blocks\n");
+			sgpnt = (struct scatterlist *) buff;
+			buff = sgpnt[sgcount].address;
+		};
 #if 0
-	if (block != *((unsigned long *) (buff+60))) {
-	    printk("%x %x :",block,  *((unsigned long *) (buff+60)));
-	    scsi_dump(SCpnt,1);
-	    panic("Bad block written.\n");
-	};
+		if (block != *((unsigned long *) (buff + 60))) {
+			printk("%x %x :", block, *((unsigned long *) (buff + 60)));
+			scsi_dump(SCpnt, 1);
+			panic("Bad block written.\n");
+		};
 #endif
-	scsi_debug_errsts = 0;
-	break;
-    case MODE_SENSE:
-        /*
-         * Used to detect write protected status.
-         */
-	scsi_debug_errsts = 0;
-        memset(buff, 0, 6);
-        break;
-    default:
-	SCSI_LOG_LLQUEUE(3,printk("Unknown command %d\n",*cmd));
-	SCpnt->result =  DID_NO_CONNECT << 16;
-	done(SCpnt);
-	return 0;
-    };
-    
-    save_flags(flags); 
-    cli();
-    for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
-        if( timeout[i].function == NULL ) break;
-    };
-    
-    /*
-     * If all of the slots are full, just return 1.  The new error handling scheme
-     * allows this, and the mid-level should queue things.
-     */
-    if (i >= SCSI_DEBUG_MAILBOXES ||  timeout[i].function != 0)
-    {
-        SCSI_LOG_LLQUEUE(1,printk("Command rejected - host busy\n"));
-        restore_flags(flags);
-        return 1;
-    }
+		scsi_debug_errsts = 0;
+		break;
+	case MODE_SENSE:
+		/*
+		 * Used to detect write protected status.
+		 */
+		scsi_debug_errsts = 0;
+		memset(buff, 0, 6);
+		break;
+	default:
+		SCSI_LOG_LLQUEUE(3, printk("Unknown command %d\n", *cmd));
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	};
+
+	save_flags(flags);
+	cli();
+	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
+		if (timeout[i].function == NULL)
+			break;
+	};
+
+	/*
+	 * If all of the slots are full, just return 1.  The new error handling scheme
+	 * allows this, and the mid-level should queue things.
+	 */
+	if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0) {
+		SCSI_LOG_LLQUEUE(1, printk("Command rejected - host busy\n"));
+		restore_flags(flags);
+		return 1;
+	}
+	SCSI_LOG_LLQUEUE(1, printk("Command accepted - slot %d\n", i));
 
-    SCSI_LOG_LLQUEUE(1,printk("Command accepted - slot %d\n", i));
-    
 #ifdef IMMEDIATE
-    if( !scsi_debug_lockup )
-    {
-        SCpnt->result = scsi_debug_errsts;
-        scsi_debug_intr_handle(i);  /* No timer - do this one right away */
-    }
-    restore_flags(flags);
+	if (!scsi_debug_lockup) {
+		SCpnt->result = scsi_debug_errsts;
+		scsi_debug_intr_handle(i);	/* No timer - do this one right away */
+	}
+	restore_flags(flags);
 #else
-        
-    SCpnt->result = scsi_debug_errsts;
-    timeout[i].function = scsi_debug_intr_handle;
-    timeout[i].data     = i;
-    timeout[i].expires  = jiffies + DISK_SPEED;
-    SCint[i]   = SCpnt;
-    do_done[i] = done;
-    
-    restore_flags(flags);
-    add_timer(&timeout[i]);
-    if (!done)
-	panic("scsi_debug_queuecommand: done can't be NULL\n");
-    
+
+	SCpnt->result = scsi_debug_errsts;
+	timeout[i].function = scsi_debug_intr_handle;
+	timeout[i].data = i;
+	timeout[i].expires = jiffies + DISK_SPEED;
+	SCint[i] = SCpnt;
+	do_done[i] = done;
+
+	restore_flags(flags);
+	add_timer(&timeout[i]);
+	if (!done)
+		panic("scsi_debug_queuecommand: done can't be NULL\n");
+
 #if 0
-    printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires,jiffies);
+	printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires, jiffies);
 #endif
 #endif
-    
-    return 0;
+
+	return 0;
 }
 
 volatile static int internal_done_flag = 0;
 volatile static int internal_done_errcode = 0;
 static void internal_done(Scsi_Cmnd * SCpnt)
 {
-    internal_done_errcode = SCpnt->result;
-    ++internal_done_flag;
+	internal_done_errcode = SCpnt->result;
+	++internal_done_flag;
 }
 
 int scsi_debug_command(Scsi_Cmnd * SCpnt)
 {
-    DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));
-    scsi_debug_queuecommand(SCpnt, internal_done);
-    
-    while (!internal_done_flag);
-    internal_done_flag = 0;
-    return internal_done_errcode;
+	DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));
+	scsi_debug_queuecommand(SCpnt, internal_done);
+
+	while (!internal_done_flag);
+	internal_done_flag = 0;
+	return internal_done_errcode;
 }
 
 /* A "high" level interrupt handler.  This should be called once per jiffy
@@ -513,184 +520,175 @@
 
 static void scsi_debug_intr_handle(unsigned long indx)
 {
-    Scsi_Cmnd * SCtmp;
-    void (*my_done)(Scsi_Cmnd *); 
+	Scsi_Cmnd *SCtmp;
+	void (*my_done) (Scsi_Cmnd *);
 #ifdef DEBUG
-    int to;
+	int to;
 #endif
-    
+
 #if 0
-    del_timer(&timeout[indx]);
+	del_timer(&timeout[indx]);
 #endif
-    
-    SCtmp                  = (Scsi_Cmnd *) SCint[indx];
-    my_done                = do_done[indx];
-    do_done[indx]          = NULL;
-    timeout[indx].function = NULL;
-    SCint[indx]            = NULL;
-    
-    if (!my_done) {
-      printk("scsi_debug_intr_handle: Unexpected interrupt\n"); 
-      return;
-    }
-    
+
+	SCtmp = (Scsi_Cmnd *) SCint[indx];
+	my_done = do_done[indx];
+	do_done[indx] = NULL;
+	timeout[indx].function = NULL;
+	SCint[indx] = NULL;
+
+	if (!my_done) {
+		printk("scsi_debug_intr_handle: Unexpected interrupt\n");
+		return;
+	}
 #ifdef DEBUG
-    printk("In intr_handle...");
-    printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
-    printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
+	printk("In intr_handle...");
+	printk("...done %d %x %d %d\n", i, my_done, to, jiffies);
+	printk("In intr_handle: %d %x %x\n", i, SCtmp, my_done);
 #endif
-    
-    my_done(SCtmp);
+
+	my_done(SCtmp);
 #ifdef DEBUG
-    printk("Called done.\n");
+	printk("Called done.\n");
 #endif
 }
 
 
 int scsi_debug_detect(Scsi_Host_Template * tpnt)
 {
-    int i;
+	int i;
 
-    for(i=0; i < NR_HOSTS_PRESENT; i++)
-    {
-        tpnt->proc_dir = &proc_scsi_scsi_debug;
-        scsi_register(tpnt,0);
-    }
-    return NR_HOSTS_PRESENT;
+	for (i = 0; i < NR_HOSTS_PRESENT; i++) {
+		tpnt->proc_dir = &proc_scsi_scsi_debug;
+		scsi_register(tpnt, 0);
+	}
+	return NR_HOSTS_PRESENT;
 }
 
 int scsi_debug_abort(Scsi_Cmnd * SCpnt)
 {
 #if 0
-    int j;
-    void (*my_done)(Scsi_Cmnd *);
-    unsigned long flags;
+	int j;
+	void (*my_done) (Scsi_Cmnd *);
+	unsigned long flags;
 #endif
-    
-    DEB(printk("scsi_debug_abort\n"));
+
+	DEB(printk("scsi_debug_abort\n"));
 #if 0
-    SCpnt->result = SCpnt->abort_reason << 16;
-    for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {
-	if(SCpnt == SCint[j]) {
-	    my_done = do_done[j];
-	    my_done(SCpnt);
-	    save_flags(flags);
-	    cli();
-	    timeout[j] = 0;
-	    SCint[j] = NULL;
-	    do_done[j] = NULL;
-	    restore_flags(flags);
+	SCpnt->result = SCpnt->abort_reason << 16;
+	for (j = 0; j < SCSI_DEBUG_MAILBOXES; j++) {
+		if (SCpnt == SCint[j]) {
+			my_done = do_done[j];
+			my_done(SCpnt);
+			save_flags(flags);
+			cli();
+			timeout[j] = 0;
+			SCint[j] = NULL;
+			do_done[j] = NULL;
+			restore_flags(flags);
+		};
 	};
-    };
 #endif
-    return SCSI_ABORT_SNOOZE;
+	return SCSI_ABORT_SNOOZE;
 }
 
-int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
-    int size = disk->capacity;
-    info[0] = N_HEAD;
-    info[1] = N_SECTOR;
-    info[2] = (size + 2047) >> 11;
-    if (info[2] >= 1024) info[2] = 1024;
-    return 0;
+int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info)
+{
+	int size = disk->capacity;
+	info[0] = N_HEAD;
+	info[1] = N_SECTOR;
+	info[2] = (size + 2047) >> 11;
+	if (info[2] >= 1024)
+		info[2] = 1024;
+	return 0;
 }
 
 int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
 {
-    int i;
-    unsigned long flags;
-    
-    void (*my_done)(Scsi_Cmnd *);
-    printk("Bus unlocked by reset - %d\n", why);
-    scsi_debug_lockup = 0;
-    DEB(printk("scsi_debug_reset called\n"));
-    for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
-        if (SCint[i] == NULL) continue;
-        SCint[i]->result = DID_RESET << 16;
-        my_done = do_done[i];
-        my_done(SCint[i]);
-        save_flags(flags);
-        cli();
-        SCint[i]            = NULL;
-        do_done[i]          = NULL;
-        timeout[i].function = NULL;
-        restore_flags(flags);
-    }
-    return SCSI_RESET_SUCCESS;
+	int i;
+	unsigned long flags;
+
+	void (*my_done) (Scsi_Cmnd *);
+	printk("Bus unlocked by reset - %d\n", why);
+	scsi_debug_lockup = 0;
+	DEB(printk("scsi_debug_reset called\n"));
+	for (i = 0; i < SCSI_DEBUG_MAILBOXES; i++) {
+		if (SCint[i] == NULL)
+			continue;
+		SCint[i]->result = DID_RESET << 16;
+		my_done = do_done[i];
+		my_done(SCint[i]);
+		save_flags(flags);
+		cli();
+		SCint[i] = NULL;
+		do_done[i] = NULL;
+		timeout[i].function = NULL;
+		restore_flags(flags);
+	}
+	return SCSI_RESET_SUCCESS;
 }
 
 const char *scsi_debug_info(void)
 {
-    static char buffer[] = " ";         /* looks nicer without anything here */
-    return buffer;
+	static char buffer[] = " ";	/* looks nicer without anything here */
+	return buffer;
 }
 
 /* scsi_debug_proc_info
  * Used if the driver currently has no own support for /proc/scsi
  */
-int scsi_debug_proc_info(char *buffer, char **start, off_t offset, 
-		     int length, int inode, int inout)
+int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
+			 int length, int inode, int inout)
 {
-    int len, pos, begin;
-    int orig_length;
+	int len, pos, begin;
+	int orig_length;
 
-    orig_length = length;
+	orig_length = length;
 
-    if(inout == 1)
-    {
-        /* First check for the Signature */
-        if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
-            buffer += 11;
-            length -= 11;
-
-            if( buffer[length - 1] == '\n' )
-            {
-                buffer[length-1] = '\0';
-                length--;
-            }
-
-            /*
-             * OK, we are getting some kind of command.  Figure out
-             * what we are supposed to do here.  Simulate bus lockups
-             * to test our reset capability.
-             */
-            if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
-            {
-                scsi_debug_lockup = 1;
-                return orig_length;
-            } 
-            
-            if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
-            {
-                scsi_debug_lockup = 0;
-                return orig_length;
-            } 
-            
-            printk("Unknown command:%s (%d)\n", buffer, length);
-        } else 
-            printk("Wrong Signature:%10s\n", (char *) buffer);
-
-        return -EINVAL;
-        
-    }
-    
-    begin = 0;
-    pos = len = sprintf(buffer, 
-			"This driver is not a real scsi driver, but it plays one on TV.\n"
-                        "It is very handy for debugging specific problems because you\n"
-                        "can simulate a variety of error conditions\n");
-    if(pos < offset)
-    {
-	len = 0;
-	begin = pos;
-    }
-    
-    *start = buffer + (offset - begin);   /* Start of wanted data */
-    len -= (offset - begin);
-    if(len > length)
-	len = length;
-    
-    return(len);
+	if (inout == 1) {
+		/* First check for the Signature */
+		if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
+			buffer += 11;
+			length -= 11;
+
+			if (buffer[length - 1] == '\n') {
+				buffer[length - 1] = '\0';
+				length--;
+			}
+			/*
+			 * OK, we are getting some kind of command.  Figure out
+			 * what we are supposed to do here.  Simulate bus lockups
+			 * to test our reset capability.
+			 */
+			if (length == 6 && strncmp(buffer, "lockup", length) == 0) {
+				scsi_debug_lockup = 1;
+				return orig_length;
+			}
+			if (length == 6 && strncmp(buffer, "unlock", length) == 0) {
+				scsi_debug_lockup = 0;
+				return orig_length;
+			}
+			printk("Unknown command:%s (%d)\n", buffer, length);
+		} else
+			printk("Wrong Signature:%10s\n", (char *) buffer);
+
+		return -EINVAL;
+
+	}
+	begin = 0;
+	pos = len = sprintf(buffer,
+	"This driver is not a real scsi driver, but it plays one on TV.\n"
+	 "It is very handy for debugging specific problems because you\n"
+			 "can simulate a variety of error conditions\n");
+	if (pos < offset) {
+		len = 0;
+		begin = pos;
+	}
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);
+	if (len > length)
+		len = length;
+
+	return (len);
 }
 
 #ifdef MODULE
@@ -699,7 +697,7 @@
 
 #include "scsi_module.c"
 #endif
- 
+
 /*
  * Overrides for Emacs so that we almost follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h
--- v2.3.16/linux/drivers/scsi/scsi_debug.h	Sun Dec 27 22:19:23 1998
+++ linux/drivers/scsi/scsi_debug.h	Sat Sep  4 10:48:46 1999
@@ -5,14 +5,14 @@
 
 int scsi_debug_detect(Scsi_Host_Template *);
 int scsi_debug_command(Scsi_Cmnd *);
-int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int scsi_debug_abort(Scsi_Cmnd *);
 int scsi_debug_biosparam(Disk *, kdev_t, int[]);
 int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
 int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
- 
+
 #ifndef NULL
-	#define NULL 0
+#define NULL 0
 #endif
 
 
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.3.16/linux/drivers/scsi/scsi_error.c	Sun Aug 15 11:49:53 1999
+++ linux/drivers/scsi/scsi_error.c	Sat Sep  4 10:48:46 1999
@@ -3,8 +3,8 @@
  *
  *  SCSI error/timeout handling
  *      Initial versions: Eric Youngdale.  Based upon conversations with
- *			  Leonard Zubkoff and David Miller at Linux Expo, 
- *			  ideas originating from all over the place.
+ *                        Leonard Zubkoff and David Miller at Linux Expo, 
+ *                        ideas originating from all over the place.
  *
  */
 
@@ -36,19 +36,19 @@
 #include "constants.h"
 
 #ifdef MODULE
-	#define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+#define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
 #else
-	#define SHUTDOWN_SIGS	(0UL)
+#define SHUTDOWN_SIGS	(0UL)
 #endif
 
 #ifdef DEBUG
-    #define SENSE_TIMEOUT SCSI_TIMEOUT
-    #define ABORT_TIMEOUT SCSI_TIMEOUT
-    #define RESET_TIMEOUT SCSI_TIMEOUT
+#define SENSE_TIMEOUT SCSI_TIMEOUT
+#define ABORT_TIMEOUT SCSI_TIMEOUT
+#define RESET_TIMEOUT SCSI_TIMEOUT
 #else
-    #define SENSE_TIMEOUT (10*HZ)
-    #define RESET_TIMEOUT (2*HZ)
-    #define ABORT_TIMEOUT (15*HZ)
+#define SENSE_TIMEOUT (10*HZ)
+#define RESET_TIMEOUT (2*HZ)
+#define ABORT_TIMEOUT (15*HZ)
 #endif
 
 #define STATIC
@@ -63,20 +63,20 @@
 
 static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.10 1997/12/08 04:50:35 eric Exp $";
 
-STATIC int         scsi_check_sense (Scsi_Cmnd * SCpnt);
-STATIC int         scsi_request_sense(Scsi_Cmnd *);
-STATIC void        scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout);
-STATIC int         scsi_try_to_abort_command(Scsi_Cmnd *, int);
-STATIC int         scsi_test_unit_ready(Scsi_Cmnd *);
-STATIC int         scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
-STATIC int         scsi_try_bus_reset(Scsi_Cmnd *);
-STATIC int         scsi_try_host_reset(Scsi_Cmnd *);
-STATIC int         scsi_unit_is_ready(Scsi_Cmnd *);
-STATIC void        scsi_eh_action_done(Scsi_Cmnd *, int);
-STATIC int         scsi_eh_retry_command(Scsi_Cmnd *);
-STATIC int	   scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
-STATIC void        scsi_restart_operations(struct Scsi_Host *);
-STATIC void        scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);
+STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt);
+STATIC int scsi_request_sense(Scsi_Cmnd *);
+STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout);
+STATIC int scsi_try_to_abort_command(Scsi_Cmnd *, int);
+STATIC int scsi_test_unit_ready(Scsi_Cmnd *);
+STATIC int scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
+STATIC int scsi_try_bus_reset(Scsi_Cmnd *);
+STATIC int scsi_try_host_reset(Scsi_Cmnd *);
+STATIC int scsi_unit_is_ready(Scsi_Cmnd *);
+STATIC void scsi_eh_action_done(Scsi_Cmnd *, int);
+STATIC int scsi_eh_retry_command(Scsi_Cmnd *);
+STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
+STATIC void scsi_restart_operations(struct Scsi_Host *);
+STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);
 
 
 /*
@@ -91,36 +91,33 @@
  *
  * Returns:     Nothing
  *
- * Notes:	This should be turned into an inline function.
+ * Notes:       This should be turned into an inline function.
  *
  * More Notes:  Each scsi command has it's own timer, and as it is added to
  *              the queue, we set up the timer.  When the command completes,
  *              we cancel the timer.  Pretty simple, really, especially
  *              compared to the old way of handling this crap.
  */
-void
-scsi_add_timer(Scsi_Cmnd * SCset, 
-			int timeout, 
-			void (*complete)(Scsi_Cmnd *))
-{
-
-    /*
-     * If the clock was already running for this command, then
-     * first delete the timer.  The timer handling code gets rather
-     * confused if we don't do this.
-     */
-    if( SCset->eh_timeout.function != NULL )
-    {
-        del_timer(&SCset->eh_timeout);
-    }
-
-    SCset->eh_timeout.data = (unsigned long) SCset;
-    SCset->eh_timeout.expires = jiffies + timeout;
-    SCset->eh_timeout.function = (void (*)(unsigned long))complete;
+void scsi_add_timer(Scsi_Cmnd * SCset,
+		    int timeout,
+		    void (*complete) (Scsi_Cmnd *))
+{
+
+	/*
+	 * If the clock was already running for this command, then
+	 * first delete the timer.  The timer handling code gets rather
+	 * confused if we don't do this.
+	 */
+	if (SCset->eh_timeout.function != NULL) {
+		del_timer(&SCset->eh_timeout);
+	}
+	SCset->eh_timeout.data = (unsigned long) SCset;
+	SCset->eh_timeout.expires = jiffies + timeout;
+	SCset->eh_timeout.function = (void (*)(unsigned long)) complete;
 
-    SCSI_LOG_ERROR_RECOVERY(5,printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
 
-    add_timer(&SCset->eh_timeout);
+	add_timer(&SCset->eh_timeout);
 
 }
 
@@ -133,22 +130,21 @@
  *
  * Returns:     Amount of time remaining before command would have timed out.
  *
- * Notes:	This should be turned into an inline function.
+ * Notes:       This should be turned into an inline function.
  */
-int
-scsi_delete_timer(Scsi_Cmnd * SCset)
+int scsi_delete_timer(Scsi_Cmnd * SCset)
 {
-  int rtn;
+	int rtn;
 
-  rtn = jiffies - SCset->eh_timeout.expires;
-  del_timer(&SCset->eh_timeout);
+	rtn = jiffies - SCset->eh_timeout.expires;
+	del_timer(&SCset->eh_timeout);
 
-  SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Clearing timer for command %p\n", SCset));
 
-  SCset->eh_timeout.data = (unsigned long) NULL;
-  SCset->eh_timeout.function = NULL;
+	SCset->eh_timeout.data = (unsigned long) NULL;
+	SCset->eh_timeout.function = NULL;
 
-  return rtn;
+	return rtn;
 }
 
 /*
@@ -162,74 +158,70 @@
  *
  * Notes:
  */
-static void do_scsi_times_out (Scsi_Cmnd * SCpnt)
+static void do_scsi_times_out(Scsi_Cmnd * SCpnt)
 {
 
-    /* 
-     * Notify the low-level code that this operation failed and we are
-     * reposessing the command.  
-     */
+	/* 
+	 * Notify the low-level code that this operation failed and we are
+	 * reposessing the command.  
+	 */
 #ifdef ERIC_neverdef
-    /*
-     * FIXME(eric)
-     * Allow the host adapter to push a queue ordering tag
-     * out to the bus to force the command in question to complete.
-     * If the host wants to do this, then we just restart the timer
-     * for the command.  Before we really do this, some real thought
-     * as to the optimum way to handle this should be done.  We *do*
-     * need to force ordering every so often to ensure that all requests
-     * do eventually complete, but I am not sure if this is the best way
-     * to actually go about it.
-     *
-     * Better yet, force a sync here, but don't block since we are in an
-     * interrupt.
-     */
-    if( SCpnt->host->hostt->eh_ordered_queue_tag )
-    {
-        if( (*SCpnt->host->hostt->eh_ordered_queue_tag)(SCpnt))
-        {
-            scsi_add_timer(SCpnt, SCpnt->internal_timeout,
-                           scsi_times_out);
-            return;
-        }
-    }
-    /*
-     * FIXME(eric) - add a second special interface to handle this
-     * case.  Ideally that interface can also be used to request
-     * a queu
-     */
-     if (SCpnt->host->can_queue)
-     {
-         SCpnt->host->hostt->queuecommand (SCpnt, NULL);
-     }
+	/*
+	 * FIXME(eric)
+	 * Allow the host adapter to push a queue ordering tag
+	 * out to the bus to force the command in question to complete.
+	 * If the host wants to do this, then we just restart the timer
+	 * for the command.  Before we really do this, some real thought
+	 * as to the optimum way to handle this should be done.  We *do*
+	 * need to force ordering every so often to ensure that all requests
+	 * do eventually complete, but I am not sure if this is the best way
+	 * to actually go about it.
+	 *
+	 * Better yet, force a sync here, but don't block since we are in an
+	 * interrupt.
+	 */
+	if (SCpnt->host->hostt->eh_ordered_queue_tag) {
+		if ((*SCpnt->host->hostt->eh_ordered_queue_tag) (SCpnt)) {
+			scsi_add_timer(SCpnt, SCpnt->internal_timeout,
+				       scsi_times_out);
+			return;
+		}
+	}
+	/*
+	 * FIXME(eric) - add a second special interface to handle this
+	 * case.  Ideally that interface can also be used to request
+	 * a queu
+	 */
+	if (SCpnt->host->can_queue) {
+		SCpnt->host->hostt->queuecommand(SCpnt, NULL);
+	}
 #endif
 
-    /* Set the serial_number_at_timeout to the current serial_number */
-    SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+	/* Set the serial_number_at_timeout to the current serial_number */
+	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+
+	SCpnt->eh_state = FAILED;
+	SCpnt->state = SCSI_STATE_TIMEOUT;
+	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+
+	SCpnt->host->in_recovery = 1;
+	SCpnt->host->host_failed++;
+
+	SCSI_LOG_TIMEOUT(3, printk("Command timed out active=%d busy=%d failed=%d\n",
+				   atomic_read(&SCpnt->host->host_active),
+				   SCpnt->host->host_busy,
+				   SCpnt->host->host_failed));
 
-    SCpnt->eh_state = FAILED;
-    SCpnt->state = SCSI_STATE_TIMEOUT;
-    SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-    
-    SCpnt->host->in_recovery = 1;
-    SCpnt->host->host_failed++;
-    
-    SCSI_LOG_TIMEOUT(3,printk("Command timed out active=%d busy=%d failed=%d\n", 
-                              atomic_read(&SCpnt->host->host_active),
-                              SCpnt->host->host_busy, 
-                              SCpnt->host->host_failed));
-    
-    /*
-     * If the host is having troubles, then look to see if this was the last
-     * command that might have failed.  If so, wake up the error handler.
-     */
-    if( SCpnt->host->host_busy == SCpnt->host->host_failed )
-    {
-        up(SCpnt->host->eh_wait);
-    }
+	/*
+	 * If the host is having troubles, then look to see if this was the last
+	 * command that might have failed.  If so, wake up the error handler.
+	 */
+	if (SCpnt->host->host_busy == SCpnt->host->host_failed) {
+		up(SCpnt->host->eh_wait);
+	}
 }
 
-void scsi_times_out (Scsi_Cmnd * SCpnt)
+void scsi_times_out(Scsi_Cmnd * SCpnt)
 {
 	unsigned long flags;
 
@@ -252,15 +244,14 @@
  * Notes:       We block until the host is out of error recovery, and then
  *              check to see whether the host or the device is offline.
  */
-int  
-scsi_block_when_processing_errors(Scsi_Device * SDpnt)
+int scsi_block_when_processing_errors(Scsi_Device * SDpnt)
 {
 
-  SCSI_SLEEP( &SDpnt->host->host_wait, SDpnt->host->in_recovery);
+	SCSI_SLEEP(&SDpnt->host->host_wait, SDpnt->host->in_recovery);
 
-  SCSI_LOG_ERROR_RECOVERY(5,printk("Open returning %d\n", SDpnt->online));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Open returning %d\n", SDpnt->online));
 
-  return SDpnt->online;
+	return SDpnt->online;
 }
 
 /*
@@ -272,39 +263,39 @@
  *
  * Returns:     Nothing.
  *
- * Notes:	During error handling, the kernel thread will be sleeping
- *		waiting for some action to complete on the device.  Our only
- *		job is to record that it timed out, and to wake up the
- *		thread.
+ * Notes:       During error handling, the kernel thread will be sleeping
+ *              waiting for some action to complete on the device.  Our only
+ *              job is to record that it timed out, and to wake up the
+ *              thread.
  */
 STATIC
-void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
+void scsi_eh_times_out(Scsi_Cmnd * SCpnt)
 {
-  unsigned long flags;
-  int rtn = FAILED;
+	unsigned long flags;
+	int rtn = FAILED;
 
-  spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 
-  SCpnt->eh_state = SCSI_STATE_TIMEOUT;
-  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	SCpnt->eh_state = SCSI_STATE_TIMEOUT;
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
-  /*
-   * As far as the low level driver is concerned, this command is still
-   * active, so we must give the low level driver a chance to abort it. (DB)
-   */
-  if (SCpnt->host->hostt->eh_abort_handler)
-     rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
+	/*
+	 * As far as the low level driver is concerned, this command is still
+	 * active, so we must give the low level driver a chance to abort it. (DB)
+	 */
+	if (SCpnt->host->hostt->eh_abort_handler)
+		rtn = SCpnt->host->hostt->eh_abort_handler(SCpnt);
 
-  SCpnt->request.rq_status = RQ_SCSI_DONE;
-  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+	SCpnt->request.rq_status = RQ_SCSI_DONE;
+	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
 
-  SCSI_LOG_ERROR_RECOVERY(5,printk("In scsi_eh_times_out %p\n", SCpnt));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("In scsi_eh_times_out %p\n", SCpnt));
 
-  if (SCpnt->host->eh_action != NULL)
-    up(SCpnt->host->eh_action);
-  else
-    printk("Missing scsi error handler thread\n");
-  spin_unlock_irqrestore(&io_request_lock, flags);
+	if (SCpnt->host->eh_action != NULL)
+		up(SCpnt->host->eh_action);
+	else
+		printk("Missing scsi error handler thread\n");
+	spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 
@@ -317,24 +308,24 @@
  *
  * Returns:     Nothing.
  *
- * Notes:	During error handling, the kernel thread will be sleeping
- *		waiting for some action to complete on the device.  Our only
- *		job is to record that the action completed, and to wake up the
- *		thread.
+ * Notes:       During error handling, the kernel thread will be sleeping
+ *              waiting for some action to complete on the device.  Our only
+ *              job is to record that the action completed, and to wake up the
+ *              thread.
  */
 STATIC
-void scsi_eh_done (Scsi_Cmnd * SCpnt)
+void scsi_eh_done(Scsi_Cmnd * SCpnt)
 {
-  SCpnt->request.rq_status = RQ_SCSI_DONE;
-  
-  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-  SCpnt->eh_state = SUCCESS;
+	SCpnt->request.rq_status = RQ_SCSI_DONE;
+
+	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+	SCpnt->eh_state = SUCCESS;
 
-  SCSI_LOG_ERROR_RECOVERY(5,printk("In eh_done %p result:%x\n", SCpnt, 
-                                   SCpnt->result));
+	SCSI_LOG_ERROR_RECOVERY(5, printk("In eh_done %p result:%x\n", SCpnt,
+					  SCpnt->result));
 
-  if (SCpnt->host->eh_action != NULL)
-    up(SCpnt->host->eh_action);
+	if (SCpnt->host->eh_action != NULL)
+		up(SCpnt->host->eh_action);
 }
 
 /*
@@ -343,208 +334,205 @@
  * Purpose:     Completion function for error handling.
  *
  * Arguments:   SCpnt   - command that is timing out.
- *		answer  - boolean that indicates whether operation succeeded.
+ *              answer  - boolean that indicates whether operation succeeded.
  *
  * Returns:     Nothing.
  *
- * Notes:	This callback is only used for abort and reset operations.
+ * Notes:       This callback is only used for abort and reset operations.
  */
 STATIC
-void scsi_eh_action_done (Scsi_Cmnd * SCpnt, int answer)
+void scsi_eh_action_done(Scsi_Cmnd * SCpnt, int answer)
 {
-  SCpnt->request.rq_status = RQ_SCSI_DONE;
-  
-  SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
-  SCpnt->eh_state = (answer ? SUCCESS : FAILED);
+	SCpnt->request.rq_status = RQ_SCSI_DONE;
 
-  if (SCpnt->host->eh_action != NULL)
-    up(SCpnt->host->eh_action);
+	SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+	SCpnt->eh_state = (answer ? SUCCESS : FAILED);
+
+	if (SCpnt->host->eh_action != NULL)
+		up(SCpnt->host->eh_action);
 }
 
 /*
- * Function:	scsi_sense_valid()
+ * Function:  scsi_sense_valid()
  *
- * Purpose:	Determine whether a host has automatically obtained sense
- *		information or not.  If we have it, then give a recommendation
- *		as to what we should do next.
+ * Purpose:     Determine whether a host has automatically obtained sense
+ *              information or not.  If we have it, then give a recommendation
+ *              as to what we should do next.
  */
-int
-scsi_sense_valid(Scsi_Cmnd * SCpnt)
+int scsi_sense_valid(Scsi_Cmnd * SCpnt)
 {
-  if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) 
-    {
-      return FALSE;
-    }
-  return TRUE;
+	if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+		return FALSE;
+	}
+	return TRUE;
 }
 
 /*
- * Function:	scsi_eh_retry_command()
+ * Function:  scsi_eh_retry_command()
  *
- * Purpose:	Retry the original command
+ * Purpose:     Retry the original command
  *
- * Returns:	SUCCESS - we were able to get the sense data.
- *		FAILED  - we were not able to get the sense data.
+ * Returns:     SUCCESS - we were able to get the sense data.
+ *              FAILED  - we were not able to get the sense data.
  * 
- * Notes:	This function will *NOT* return until the command either
- *		times out, or it completes.
+ * Notes:       This function will *NOT* return until the command either
+ *              times out, or it completes.
  */
-STATIC int
-scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
+STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
 {
-  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
-          sizeof(SCpnt->data_cmnd));
-  SCpnt->request_buffer = SCpnt->buffer;
-  SCpnt->request_bufflen = SCpnt->bufflen;
-  SCpnt->use_sg = SCpnt->old_use_sg;
-  SCpnt->cmd_len = SCpnt->old_cmd_len;
+	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+	       sizeof(SCpnt->data_cmnd));
+	SCpnt->request_buffer = SCpnt->buffer;
+	SCpnt->request_bufflen = SCpnt->bufflen;
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->cmd_len = SCpnt->old_cmd_len;
 
-  scsi_send_eh_cmnd (SCpnt, SCpnt->timeout_per_command);
+	scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
 
-  /*
-   * Hey, we are done.  Let's look to see what happened.
-   */
-  return SCpnt->eh_state;
+	/*
+	 * Hey, we are done.  Let's look to see what happened.
+	 */
+	return SCpnt->eh_state;
 }
 
 /*
- * Function:	scsi_request_sense()
+ * Function:  scsi_request_sense()
  *
- * Purpose:	Request sense data from a particular target.
+ * Purpose:     Request sense data from a particular target.
  *
- * Returns:	SUCCESS - we were able to get the sense data.
- *		FAILED  - we were not able to get the sense data.
+ * Returns:     SUCCESS - we were able to get the sense data.
+ *              FAILED  - we were not able to get the sense data.
  * 
- * Notes:	Some hosts automatically obtain this information, others
- *		require that we obtain it on our own.
+ * Notes:       Some hosts automatically obtain this information, others
+ *              require that we obtain it on our own.
  *
- *		This function will *NOT* return until the command either
- *		times out, or it completes.
+ *              This function will *NOT* return until the command either
+ *              times out, or it completes.
  */
-STATIC int
-scsi_request_sense(Scsi_Cmnd * SCpnt)
+STATIC int scsi_request_sense(Scsi_Cmnd * SCpnt)
 {
-  static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
-  unsigned char scsi_result0[256], *scsi_result=NULL;
-
-
-  memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
-	  sizeof(generic_sense));
-
-  SCpnt->cmnd[1] = SCpnt->lun << 5;
-
-  scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
-             ? &scsi_result0[0] : scsi_init_malloc (512, GFP_ATOMIC|GFP_DMA);
-
-  if (scsi_result == NULL) {
-     printk("cannot allocate scsi_result in scsi_request_sense.\n");
-     return FAILED;
-     }
-
-  /*
-   * Zero the sense buffer.  Some host adapters automatically always request
-   * sense, so it is not a good idea that SCpnt->request_buffer and
-   * SCpnt->sense_buffer point to the same address (DB).
-   * 0 is not a valid sense code. 
-   */
-  memset ((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-  memset ((void *) scsi_result, 0, 256);
-
-  SCpnt->request_buffer = scsi_result;
-  SCpnt->request_bufflen = 256;
-  SCpnt->use_sg = 0;
-  SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-
-  scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
-
-  /* Last chance to have valid sense data */
-  if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer,
-                                                SCpnt->request_buffer,
-                                                sizeof(SCpnt->sense_buffer));
-
-  if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-        scsi_init_free (scsi_result, 512);
-
-  /*
-   * When we eventually call scsi_finish, we really wish to complete
-   * the original request, so let's restore the original data. (DB)
-   */
-  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
-          sizeof(SCpnt->data_cmnd));
-  SCpnt->request_buffer = SCpnt->buffer;
-  SCpnt->request_bufflen = SCpnt->bufflen;
-  SCpnt->use_sg = SCpnt->old_use_sg;
-  SCpnt->cmd_len = SCpnt->old_cmd_len;
-
-  /*
-   * Hey, we are done.  Let's look to see what happened.
-   */
-  return SCpnt->eh_state;
-}
-
-/*
- * Function:	scsi_test_unit_ready()
- *
- * Purpose:	Run test unit ready command to see if the device is talking to us or not.
- *
- */
-STATIC int
-scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
-{
-  static unsigned char tur_command[6] = {TEST_UNIT_READY, 0,0,0,0,0};
-  unsigned char scsi_result0[256], *scsi_result=NULL;
-
-  memcpy ((void *) SCpnt->cmnd , (void *) tur_command,
-	  sizeof(tur_command));
-
-  SCpnt->cmnd[1] = SCpnt->lun << 5;
-
-  scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
-             ? &scsi_result0[0] : scsi_init_malloc (512, GFP_ATOMIC|GFP_DMA);
-
-  if (scsi_result == NULL) {
-     printk("cannot allocate scsi_result in scsi_test_unit_ready.\n");
-     return FAILED;
-     }
-
-  /*
-   * Zero the sense buffer.  Some host adapters automatically always request
-   * sense, so it is not a good idea that SCpnt->request_buffer and
-   * SCpnt->sense_buffer point to the same address (DB).
-   * 0 is not a valid sense code. 
-   */
-  memset ((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-  memset ((void *) scsi_result, 0, 256);
-
-  SCpnt->request_buffer = scsi_result;
-  SCpnt->request_bufflen = 256;
-  SCpnt->use_sg = 0;
-  SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-  scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
-
-  /* Last chance to have valid sense data */
-  if (!scsi_sense_valid(SCpnt)) memcpy((void *) SCpnt->sense_buffer,
-                                                SCpnt->request_buffer,
-                                                sizeof(SCpnt->sense_buffer));
-
-  if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
-        scsi_init_free (scsi_result, 512);
-
-  /*
-   * When we eventually call scsi_finish, we really wish to complete
-   * the original request, so let's restore the original data. (DB)
-   */
-  memcpy ((void *) SCpnt->cmnd,  (void*) SCpnt->data_cmnd,
-          sizeof(SCpnt->data_cmnd));
-  SCpnt->request_buffer = SCpnt->buffer;
-  SCpnt->request_bufflen = SCpnt->bufflen;
-  SCpnt->use_sg = SCpnt->old_use_sg;
-  SCpnt->cmd_len = SCpnt->old_cmd_len;
-
-  /*
-   * Hey, we are done.  Let's look to see what happened.
-   */
-  return SCpnt->eh_state;
+	static unsigned char generic_sense[6] =
+	{REQUEST_SENSE, 0, 0, 0, 255, 0};
+	unsigned char scsi_result0[256], *scsi_result = NULL;
+
+
+	memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
+	       sizeof(generic_sense));
+
+	SCpnt->cmnd[1] = SCpnt->lun << 5;
+
+	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
+	    ? &scsi_result0[0] : scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
+
+	if (scsi_result == NULL) {
+		printk("cannot allocate scsi_result in scsi_request_sense.\n");
+		return FAILED;
+	}
+	/*
+	 * Zero the sense buffer.  Some host adapters automatically always request
+	 * sense, so it is not a good idea that SCpnt->request_buffer and
+	 * SCpnt->sense_buffer point to the same address (DB).
+	 * 0 is not a valid sense code. 
+	 */
+	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+	memset((void *) scsi_result, 0, 256);
+
+	SCpnt->request_buffer = scsi_result;
+	SCpnt->request_bufflen = 256;
+	SCpnt->use_sg = 0;
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+
+	/* Last chance to have valid sense data */
+	if (!scsi_sense_valid(SCpnt))
+		memcpy((void *) SCpnt->sense_buffer,
+		       SCpnt->request_buffer,
+		       sizeof(SCpnt->sense_buffer));
+
+	if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+		scsi_init_free(scsi_result, 512);
+
+	/*
+	 * When we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (DB)
+	 */
+	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+	       sizeof(SCpnt->data_cmnd));
+	SCpnt->request_buffer = SCpnt->buffer;
+	SCpnt->request_bufflen = SCpnt->bufflen;
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->cmd_len = SCpnt->old_cmd_len;
+
+	/*
+	 * Hey, we are done.  Let's look to see what happened.
+	 */
+	return SCpnt->eh_state;
+}
+
+/*
+ * Function:  scsi_test_unit_ready()
+ *
+ * Purpose:     Run test unit ready command to see if the device is talking to us or not.
+ *
+ */
+STATIC int scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
+{
+	static unsigned char tur_command[6] =
+	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
+	unsigned char scsi_result0[256], *scsi_result = NULL;
+
+	memcpy((void *) SCpnt->cmnd, (void *) tur_command,
+	       sizeof(tur_command));
+
+	SCpnt->cmnd[1] = SCpnt->lun << 5;
+
+	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
+	    ? &scsi_result0[0] : scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
+
+	if (scsi_result == NULL) {
+		printk("cannot allocate scsi_result in scsi_test_unit_ready.\n");
+		return FAILED;
+	}
+	/*
+	 * Zero the sense buffer.  Some host adapters automatically always request
+	 * sense, so it is not a good idea that SCpnt->request_buffer and
+	 * SCpnt->sense_buffer point to the same address (DB).
+	 * 0 is not a valid sense code. 
+	 */
+	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+	memset((void *) scsi_result, 0, 256);
+
+	SCpnt->request_buffer = scsi_result;
+	SCpnt->request_bufflen = 256;
+	SCpnt->use_sg = 0;
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
+
+	/* Last chance to have valid sense data */
+	if (!scsi_sense_valid(SCpnt))
+		memcpy((void *) SCpnt->sense_buffer,
+		       SCpnt->request_buffer,
+		       sizeof(SCpnt->sense_buffer));
+
+	if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+		scsi_init_free(scsi_result, 512);
+
+	/*
+	 * When we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (DB)
+	 */
+	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+	       sizeof(SCpnt->data_cmnd));
+	SCpnt->request_buffer = SCpnt->buffer;
+	SCpnt->request_bufflen = SCpnt->bufflen;
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	SCpnt->cmd_len = SCpnt->old_cmd_len;
+
+	/*
+	 * Hey, we are done.  Let's look to see what happened.
+	 */
+	return SCpnt->eh_state;
 }
 
 /*
@@ -553,164 +541,146 @@
  * to be locked we can avoid the lock here..
  */
 STATIC
-void scsi_sleep_done (struct semaphore * sem)
+void scsi_sleep_done(struct semaphore *sem)
 {
-    if( sem != NULL )
-    {
-        up(sem);
-    }
+	if (sem != NULL) {
+		up(sem);
+	}
 }
 
 
-void scsi_sleep (int timeout)
+void scsi_sleep(int timeout)
 {
-    DECLARE_MUTEX_LOCKED(sem);
-    struct timer_list timer;
+	DECLARE_MUTEX_LOCKED(sem);
+	struct timer_list timer;
 
-    init_timer(&timer);
-    timer.data = (unsigned long) &sem;
-    timer.expires = jiffies + timeout;
-    timer.function = (void (*)(unsigned long))scsi_sleep_done;
-    
-    SCSI_LOG_ERROR_RECOVERY(5,printk("Sleeping for timer tics %d\n", timeout));
-    
-    add_timer(&timer);
+	init_timer(&timer);
+	timer.data = (unsigned long) &sem;
+	timer.expires = jiffies + timeout;
+	timer.function = (void (*)(unsigned long)) scsi_sleep_done;
 
-    spin_unlock_irq(&io_request_lock);
-    down(&sem);
-    spin_lock_irq(&io_request_lock);
-    
-    del_timer(&timer);
+	SCSI_LOG_ERROR_RECOVERY(5, printk("Sleeping for timer tics %d\n", timeout));
+
+	add_timer(&timer);
+
+	spin_unlock_irq(&io_request_lock);
+	down(&sem);
+	spin_lock_irq(&io_request_lock);
+
+	del_timer(&timer);
 }
 
 /*
- * Function:	scsi_send_eh_cmnd
+ * Function:  scsi_send_eh_cmnd
  *
- * Purpose:	Send a command out to a device as part of error recovery.
+ * Purpose:     Send a command out to a device as part of error recovery.
  *
- * Notes:	The initialization of the structures is quite a bit different
- *		in this case, and furthermore, there is a different completion
- *		handler.
+ * Notes:       The initialization of the structures is quite a bit different
+ *              in this case, and furthermore, there is a different completion
+ *              handler.
  */
-STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout)
+STATIC void scsi_send_eh_cmnd(Scsi_Cmnd * SCpnt, int timeout)
 {
-    struct Scsi_Host * host;
-
-    host = SCpnt->host;
-
-retry:
-    /*
-     * We will use a queued command if possible, otherwise we will emulate the
-     * queuing and calling of completion function ourselves.
-     */
-    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-
-    if (host->can_queue)
-    {
-        DECLARE_MUTEX_LOCKED(sem);
-
-        SCpnt->eh_state = SCSI_STATE_QUEUED;
+	struct Scsi_Host *host;
 
-        scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
+	host = SCpnt->host;
 
+      retry:
 	/*
-	 * Set up the semaphore so we wait for the command to complete.
+	 * We will use a queued command if possible, otherwise we will emulate the
+	 * queuing and calling of completion function ourselves.
 	 */
-	SCpnt->host->eh_action = &sem;
-	SCpnt->request.rq_status = RQ_SCSI_BUSY;
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
-	host->hostt->queuecommand (SCpnt, scsi_eh_done);
-        spin_unlock_irq(&io_request_lock);
-        down(&sem);
-        spin_lock_irq(&io_request_lock);
+	if (host->can_queue) {
+		DECLARE_MUTEX_LOCKED(sem);
 
-        SCpnt->host->eh_action = NULL;
+		SCpnt->eh_state = SCSI_STATE_QUEUED;
 
-	del_timer(&SCpnt->eh_timeout);
+		scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
 
-	/*
-	 * See if timeout.  If so, tell the host to forget about it.
-	 * In other words, we don't want a callback any more.
-	 */
-	if( SCpnt->eh_state == SCSI_STATE_TIMEOUT )
-	  {
-	    SCpnt->eh_state = FAILED;
-	  }
-
-        SCSI_LOG_ERROR_RECOVERY(5,printk("send_eh_cmnd: %p eh_state:%x\n", 
-                                         SCpnt, SCpnt->eh_state));
-    }
-    else
-      {
-	int temp;
+		/*
+		 * Set up the semaphore so we wait for the command to complete.
+		 */
+		SCpnt->host->eh_action = &sem;
+		SCpnt->request.rq_status = RQ_SCSI_BUSY;
+
+		host->hostt->queuecommand(SCpnt, scsi_eh_done);
+		spin_unlock_irq(&io_request_lock);
+		down(&sem);
+		spin_lock_irq(&io_request_lock);
+
+		SCpnt->host->eh_action = NULL;
+
+		del_timer(&SCpnt->eh_timeout);
+
+		/*
+		 * See if timeout.  If so, tell the host to forget about it.
+		 * In other words, we don't want a callback any more.
+		 */
+		if (SCpnt->eh_state == SCSI_STATE_TIMEOUT) {
+			SCpnt->eh_state = FAILED;
+		}
+		SCSI_LOG_ERROR_RECOVERY(5, printk("send_eh_cmnd: %p eh_state:%x\n",
+						SCpnt, SCpnt->eh_state));
+	} else {
+		int temp;
+
+		/*
+		 * We damn well had better never use this code.  There is no timeout
+		 * protection here, since we would end up waiting in the actual low
+		 * level driver, we don't know how to wake it up.
+		 */
+		temp = host->hostt->command(SCpnt);
+		SCpnt->result = temp;
+		if (scsi_eh_completed_normally(SCpnt)) {
+			SCpnt->eh_state = SUCCESS;
+		} else {
+			SCpnt->eh_state = FAILED;
+		}
+	}
 
 	/*
-	 * We damn well had better never use this code.  There is no timeout
-	 * protection here, since we would end up waiting in the actual low
-	 * level driver, we don't know how to wake it up.
+	 * Now examine the actual status codes to see whether the command actually
+	 * did complete normally.
 	 */
-	temp = host->hostt->command (SCpnt);
-	SCpnt->result = temp;
-	if( scsi_eh_completed_normally(SCpnt) )
-	  {
-	    SCpnt->eh_state = SUCCESS;
-	  }
-	else
-	  {
-	    SCpnt->eh_state = FAILED;
-	  }
-      }
-
-    /*
-     * Now examine the actual status codes to see whether the command actually
-     * did complete normally.
-     */
-    if( SCpnt->eh_state == SUCCESS )
-      {
-	switch( scsi_eh_completed_normally(SCpnt) )
-	  {
-	  case SUCCESS:
-	    SCpnt->eh_state = SUCCESS;
-	    break;
-	  case NEEDS_RETRY:
-	    goto retry;
-	  case FAILED:
-	  default:
-	    SCpnt->eh_state = FAILED;
-	    break;
-	  }
-      }
-    else
-      {
-	SCpnt->eh_state = FAILED;
-      }
+	if (SCpnt->eh_state == SUCCESS) {
+		switch (scsi_eh_completed_normally(SCpnt)) {
+		case SUCCESS:
+			SCpnt->eh_state = SUCCESS;
+			break;
+		case NEEDS_RETRY:
+			goto retry;
+		case FAILED:
+		default:
+			SCpnt->eh_state = FAILED;
+			break;
+		}
+	} else {
+		SCpnt->eh_state = FAILED;
+	}
 }
 
 /*
- * Function:	scsi_unit_is_ready()
+ * Function:  scsi_unit_is_ready()
  *
- * Purpose:	Called after TEST_UNIT_READY is run, to test to see if
- *		the unit responded in a way that indicates it is ready.
+ * Purpose:     Called after TEST_UNIT_READY is run, to test to see if
+ *              the unit responded in a way that indicates it is ready.
  */
-STATIC int
-scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
-{
-  if (SCpnt->result) 
-    {
-      if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
-	   (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
-	  ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) 
-	{
-	  if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
-	      ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
-	      ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST))
-	    {
-	      return 0;
-	    }
-	}
-    }
-  
-  return 1;
+STATIC int scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
+{
+	if (SCpnt->result) {
+		if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
+		     (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
+		    ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
+			if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+			    ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+			    ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST)) {
+				return 0;
+			}
+		}
+	}
+	return 1;
 }
 
 /*
@@ -727,206 +697,190 @@
  *              a list of pending commands for final completion, and once we
  *              are ready to leave error handling we handle completion for real.
  */
-STATIC void
-scsi_eh_finish_command(Scsi_Cmnd **SClist, Scsi_Cmnd * SCpnt)
+STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt)
 {
-    SCpnt->state = SCSI_STATE_BHQUEUE;
-    SCpnt->bh_next = *SClist;
-    /*
-     * Set this back so that the upper level can correctly free up
-     * things.
-     */
-    SCpnt->use_sg = SCpnt->old_use_sg;
-    *SClist = SCpnt;
+	SCpnt->state = SCSI_STATE_BHQUEUE;
+	SCpnt->bh_next = *SClist;
+	/*
+	 * Set this back so that the upper level can correctly free up
+	 * things.
+	 */
+	SCpnt->use_sg = SCpnt->old_use_sg;
+	*SClist = SCpnt;
 }
 
 /*
- * Function:	scsi_try_to_abort_command
+ * Function:  scsi_try_to_abort_command
  *
- * Purpose:	Ask host adapter to abort a running command.
+ * Purpose:     Ask host adapter to abort a running command.
  *
- * Returns:	FAILED		Operation failed or not supported.
- *		SUCCESS		Succeeded.
+ * Returns:     FAILED          Operation failed or not supported.
+ *              SUCCESS         Succeeded.
  *
- * Notes:	This function will not return until the user's completion
- *		function has been called.  There is no timeout on this
+ * Notes:       This function will not return until the user's completion
+ *              function has been called.  There is no timeout on this
  *              operation.  If the author of the low-level driver wishes
  *              this operation to be timed, they can provide this facility
  *              themselves.  Helper functions in scsi_error.c can be supplied
  *              to make this easier to do.
  *
- * Notes:	It may be possible to combine this with all of the reset
- *		handling to eliminate a lot of code duplication.  I don't
- *		know what makes more sense at the moment - this is just a
- *		prototype.
+ * Notes:       It may be possible to combine this with all of the reset
+ *              handling to eliminate a lot of code duplication.  I don't
+ *              know what makes more sense at the moment - this is just a
+ *              prototype.
  */
-STATIC int
-scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
+STATIC int scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
 {
-  SCpnt->eh_state = FAILED; /* Until we come up with something better */
-
-  if( SCpnt->host->hostt->eh_abort_handler == NULL )
-    {
-      return FAILED;
-    }
+	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
 
-  /* 
-   * scsi_done was called just after the command timed out and before
-   * we had a chance to process it. (DB)
-   */
-  if (SCpnt->serial_number == 0) return SUCCESS;
+	if (SCpnt->host->hostt->eh_abort_handler == NULL) {
+		return FAILED;
+	}
+	/* 
+	 * scsi_done was called just after the command timed out and before
+	 * we had a chance to process it. (DB)
+	 */
+	if (SCpnt->serial_number == 0)
+		return SUCCESS;
 
-  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
-  return SCpnt->host->hostt->eh_abort_handler(SCpnt);
+	return SCpnt->host->hostt->eh_abort_handler(SCpnt);
 }
 
 /*
- * Function:	scsi_try_bus_device_reset
+ * Function:  scsi_try_bus_device_reset
  *
- * Purpose:	Ask host adapter to perform a bus device reset for a given
- *		device.
+ * Purpose:     Ask host adapter to perform a bus device reset for a given
+ *              device.
  *
- * Returns:	FAILED		Operation failed or not supported.
- *		SUCCESS		Succeeded.
+ * Returns:     FAILED          Operation failed or not supported.
+ *              SUCCESS         Succeeded.
  *
- * Notes:	There is no timeout for this operation.  If this operation is
+ * Notes:       There is no timeout for this operation.  If this operation is
  *              unreliable for a given host, then the host itself needs to put a
  *              timer on it, and set the host back to a consistent state prior
  *              to returning.
  */
-STATIC int
-scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
+STATIC int scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
 {
-  int		   rtn;
+	int rtn;
+
+	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
 
-  SCpnt->eh_state = FAILED; /* Until we come up with something better */
+	if (SCpnt->host->hostt->eh_device_reset_handler == NULL) {
+		return FAILED;
+	}
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
 
-  if( SCpnt->host->hostt->eh_device_reset_handler == NULL )
-    {
-      return FAILED;
-    }
-  
-  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-    
-  rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
+	rtn = SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
 
-  if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS;
+	if (rtn == SUCCESS)
+		SCpnt->eh_state = SUCCESS;
 
-  return SCpnt->eh_state;
+	return SCpnt->eh_state;
 }
 
 /*
- * Function:	scsi_try_bus_reset
+ * Function:  scsi_try_bus_reset
  *
- * Purpose:	Ask host adapter to perform a bus reset for a host.
+ * Purpose:     Ask host adapter to perform a bus reset for a host.
  *
- * Returns:	FAILED		Operation failed or not supported.
- *		SUCCESS		Succeeded.
+ * Returns:     FAILED          Operation failed or not supported.
+ *              SUCCESS         Succeeded.
  *
- * Notes:	
+ * Notes:       
  */
-STATIC int
-scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
+STATIC int scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
 {
-  int		   rtn;
-
-  SCpnt->eh_state = FAILED; /* Until we come up with something better */
-  SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-  SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+	int rtn;
 
-  if( SCpnt->host->hostt->eh_bus_reset_handler == NULL )
-    {
-      return FAILED;
-    }
+	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
 
-  rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
+	if (SCpnt->host->hostt->eh_bus_reset_handler == NULL) {
+		return FAILED;
+	}
+	rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
 
-  if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS;
+	if (rtn == SUCCESS)
+		SCpnt->eh_state = SUCCESS;
 
-  /*
-   * If we had a successful bus reset, mark the command blocks to expect
-   * a condition code of unit attention.
-   */
-  scsi_sleep(BUS_RESET_SETTLE_TIME);
-  if( SCpnt->eh_state == SUCCESS )
-    {
-      Scsi_Device * SDloop;
-      for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
-	{
-            if( SCpnt->channel == SDloop->channel )
-            {
-                SDloop->was_reset = 1;
-                SDloop->expecting_cc_ua = 1;
-            }
+	/*
+	 * If we had a successful bus reset, mark the command blocks to expect
+	 * a condition code of unit attention.
+	 */
+	scsi_sleep(BUS_RESET_SETTLE_TIME);
+	if (SCpnt->eh_state == SUCCESS) {
+		Scsi_Device *SDloop;
+		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
+			if (SCpnt->channel == SDloop->channel) {
+				SDloop->was_reset = 1;
+				SDloop->expecting_cc_ua = 1;
+			}
+		}
 	}
-    }
-
-  return SCpnt->eh_state;
+	return SCpnt->eh_state;
 }
 
 /*
- * Function:	scsi_try_host_reset
+ * Function:  scsi_try_host_reset
  *
- * Purpose:	Ask host adapter to reset itself, and the bus.
+ * Purpose:     Ask host adapter to reset itself, and the bus.
  *
- * Returns:	FAILED		Operation failed or not supported.
- *		SUCCESS		Succeeded.
+ * Returns:     FAILED          Operation failed or not supported.
+ *              SUCCESS         Succeeded.
  *
  * Notes:
  */
-STATIC int
-scsi_try_host_reset(Scsi_Cmnd * SCpnt)
+STATIC int scsi_try_host_reset(Scsi_Cmnd * SCpnt)
 {
-    int		   rtn;
+	int rtn;
 
-    SCpnt->eh_state = FAILED; /* Until we come up with something better */
-    SCpnt->owner = SCSI_OWNER_LOWLEVEL;
-    SCpnt->serial_number_at_timeout = SCpnt->serial_number;
-    
-    if( SCpnt->host->hostt->eh_host_reset_handler == NULL )
-    {
-        return FAILED;
-    }
-    
-    rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
-
-    if (rtn == SUCCESS) SCpnt->eh_state = SUCCESS;
-
-    /*
-     * If we had a successful host reset, mark the command blocks to expect
-     * a condition code of unit attention.
-     */
-    scsi_sleep(HOST_RESET_SETTLE_TIME);
-    if( SCpnt->eh_state == SUCCESS )
-    {
-        Scsi_Device * SDloop;
-        for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
-	{
-            SDloop->was_reset = 1;
-            SDloop->expecting_cc_ua = 1;
-	}
-    }
-    
-    return SCpnt->eh_state;
+	SCpnt->eh_state = FAILED;	/* Until we come up with something better */
+	SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+
+	if (SCpnt->host->hostt->eh_host_reset_handler == NULL) {
+		return FAILED;
+	}
+	rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
+
+	if (rtn == SUCCESS)
+		SCpnt->eh_state = SUCCESS;
+
+	/*
+	 * If we had a successful host reset, mark the command blocks to expect
+	 * a condition code of unit attention.
+	 */
+	scsi_sleep(HOST_RESET_SETTLE_TIME);
+	if (SCpnt->eh_state == SUCCESS) {
+		Scsi_Device *SDloop;
+		for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next) {
+			SDloop->was_reset = 1;
+			SDloop->expecting_cc_ua = 1;
+		}
+	}
+	return SCpnt->eh_state;
 }
 
 /*
- * Function:	scsi_decide_disposition
- *
- * Purpose:	Examine a command block that has come back from the low-level
- *		and figure out what to do next.
- *
- * Returns:	SUCCESS		- pass on to upper level.
- *		FAILED		- pass on to error handler thread.
- *		RETRY		- command should be retried.
- *		SOFTERR		- command succeeded, but we need to log
- *				  a soft error.
- *
- * Notes:	This is *ONLY* called when we are examining the status
- *		after sending out the actual data command.  Any commands
- *		that are queued for error recovery (i.e. TEST_UNIT_READY)
- *		do *NOT* come through here.
+ * Function:  scsi_decide_disposition
+ *
+ * Purpose:     Examine a command block that has come back from the low-level
+ *              and figure out what to do next.
+ *
+ * Returns:     SUCCESS         - pass on to upper level.
+ *              FAILED          - pass on to error handler thread.
+ *              RETRY           - command should be retried.
+ *              SOFTERR         - command succeeded, but we need to log
+ *                                a soft error.
+ *
+ * Notes:       This is *ONLY* called when we are examining the status
+ *              after sending out the actual data command.  Any commands
+ *              that are queued for error recovery (i.e. TEST_UNIT_READY)
+ *              do *NOT* come through here.
  *
  *              NOTE - When this routine returns FAILED, it means the error
  *              handler thread is woken.  In cases where the error code
@@ -934,419 +888,383 @@
  *              thread (i.e. we don't need to abort/reset), then this function
  *              should return SUCCESS.
  */
-int scsi_decide_disposition (Scsi_Cmnd * SCpnt)
+int scsi_decide_disposition(Scsi_Cmnd * SCpnt)
 {
-  int	rtn;
+	int rtn;
+
+	/*
+	 * If the device is offline, then we clearly just pass the result back
+	 * up to the top level.
+	 */
+	if (SCpnt->device->online == FALSE) {
+		SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: device offline - report as SUCCESS\n"));
+		return SUCCESS;
+	}
+	/*
+	 * First check the host byte, to see if there is anything in there
+	 * that would indicate what we need to do.
+	 */
+
+	switch (host_byte(SCpnt->result)) {
+	case DID_PASSTHROUGH:
+		/*
+		 * No matter what, pass this through to the upper layer.
+		 * Nuke this special code so that it looks like we are saying
+		 * DID_OK.
+		 */
+		SCpnt->result &= 0xff00ffff;
+		return SUCCESS;
+	case DID_OK:
+		/*
+		 * Looks good.  Drop through, and check the next byte.
+		 */
+		break;
+	case DID_NO_CONNECT:
+	case DID_BAD_TARGET:
+	case DID_ABORT:
+		/*
+		 * Note - this means that we just report the status back to the
+		 * top level driver, not that we actually think that it indicates
+		 * success.
+		 */
+		return SUCCESS;
+		/*
+		 * When the low level driver returns DID_SOFT_ERROR,
+		 * it is responsible for keeping an internal retry counter 
+		 * in order to avoid endless loops (DB)
+		 */
+	case DID_SOFT_ERROR:
+		return NEEDS_RETRY;
+
+	case DID_BUS_BUSY:
+	case DID_PARITY:
+	case DID_ERROR:
+		goto maybe_retry;
+	case DID_TIME_OUT:
+		/*
+		   * When we scan the bus, we get timeout messages for
+		   * these commands if there is no device available.
+		   * Other hosts report DID_NO_CONNECT for the same thing.
+		 */
+		if ((SCpnt->cmnd[0] == TEST_UNIT_READY ||
+		     SCpnt->cmnd[0] == INQUIRY)) {
+			return SUCCESS;
+		} else {
+			return FAILED;
+		}
+	case DID_RESET:
+		/*
+		 * In the normal case where we haven't initiated a reset, this is
+		 * a failure.
+		 */
+		if (SCpnt->flags & IS_RESETTING) {
+			SCpnt->flags &= ~IS_RESETTING;
+			goto maybe_retry;
+		}
+		/*
+		 * Examine the sense data to figure out how to proceed from here.
+		 * If there is no sense data, we will be forced into the error
+		 * handler thread, where we get to examine the thing in a lot more
+		 * detail.
+		 */
+		return scsi_check_sense(SCpnt);
+	default:
+		return FAILED;
+	}
+
+	/*
+	 * Next, check the message byte.
+	 */
+	if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) {
+		return FAILED;
+	}
+	/*
+	 * Now, check the status byte to see if this indicates anything special.
+	 */
+	switch (status_byte(SCpnt->result)) {
+	case QUEUE_FULL:
+		/*
+		 * The case of trying to send too many commands to a tagged queueing
+		 * device.
+		 */
+		return ADD_TO_MLQUEUE;
+	case GOOD:
+	case COMMAND_TERMINATED:
+		return SUCCESS;
+	case CHECK_CONDITION:
+		rtn = scsi_check_sense(SCpnt);
+		if (rtn == NEEDS_RETRY) {
+			goto maybe_retry;
+		}
+		return rtn;
+	case CONDITION_GOOD:
+	case INTERMEDIATE_GOOD:
+	case INTERMEDIATE_C_GOOD:
+		/*
+		 * Who knows?  FIXME(eric)
+		 */
+		return SUCCESS;
+	case BUSY:
+	case RESERVATION_CONFLICT:
+		goto maybe_retry;
+	default:
+		return FAILED;
+	}
+	return FAILED;
+
+      maybe_retry:
+
+	if ((++SCpnt->retries) < SCpnt->allowed) {
+		return NEEDS_RETRY;
+	} else {
+		return FAILED;
+	}
+}
 
-  /*
-   * If the device is offline, then we clearly just pass the result back
-   * up to the top level.
-   */
-  if( SCpnt->device->online == FALSE )
-  {
-      SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: device offline - report as SUCCESS\n"));
-      return SUCCESS;
-  }
-
-  /*
-   * First check the host byte, to see if there is anything in there
-   * that would indicate what we need to do.
-   */
-
-  switch(host_byte(SCpnt->result))
-    {
-    case DID_PASSTHROUGH:
-        /*
-         * No matter what, pass this through to the upper layer.
-         * Nuke this special code so that it looks like we are saying
-         * DID_OK.
-         */
-        SCpnt->result &= 0xff00ffff;
-        return SUCCESS;
-    case DID_OK:
-      /*
-       * Looks good.  Drop through, and check the next byte.
-       */
-      break;
-    case DID_NO_CONNECT:
-    case DID_BAD_TARGET:
-    case DID_ABORT:
-      /*
-       * Note - this means that we just report the status back to the
-       * top level driver, not that we actually think that it indicates
-       * success.
-       */
-      return SUCCESS;
-      /*
-       * When the low level driver returns DID_SOFT_ERROR,
-       * it is responsible for keeping an internal retry counter 
-       * in order to avoid endless loops (DB)
-       */
-    case DID_SOFT_ERROR:
-      return NEEDS_RETRY;
-
-    case DID_BUS_BUSY:
-    case DID_PARITY:
-    case DID_ERROR:
-      goto maybe_retry;
-    case DID_TIME_OUT:
-      /*
-         * When we scan the bus, we get timeout messages for
-         * these commands if there is no device available.
-         * Other hosts report DID_NO_CONNECT for the same thing.
-         */
-        if( (SCpnt->cmnd[0] == TEST_UNIT_READY ||
-             SCpnt->cmnd[0] == INQUIRY) )
-        {
-            return SUCCESS;
-        }
-        else
-        {
-            return FAILED;
-        }
-    case DID_RESET:
-      /*
-       * In the normal case where we haven't initiated a reset, this is
-       * a failure.
-       */
-      if( SCpnt->flags & IS_RESETTING )
-	{
-	  SCpnt->flags &= ~IS_RESETTING;
-	  goto maybe_retry;
-	}
-
-      /*
-       * Examine the sense data to figure out how to proceed from here.
-       * If there is no sense data, we will be forced into the error
-       * handler thread, where we get to examine the thing in a lot more
-       * detail.
-       */
-      return scsi_check_sense (SCpnt);
-    default:
-      return FAILED;
-    }
-
-  /*
-   * Next, check the message byte.
-   */
-  if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
-    {
-      return FAILED;
-    }
-
-  /*
-   * Now, check the status byte to see if this indicates anything special.
-   */
-  switch (status_byte(SCpnt->result))
-    {
-    case QUEUE_FULL:
-      /*
-       * The case of trying to send too many commands to a tagged queueing
-       * device.
-       */
-      return ADD_TO_MLQUEUE;
-    case GOOD:
-    case COMMAND_TERMINATED:
-      return SUCCESS;
-    case CHECK_CONDITION:
-      rtn = scsi_check_sense(SCpnt);
-      if( rtn == NEEDS_RETRY )
-	{
-	  goto maybe_retry;
-	}
-      return rtn;
-    case CONDITION_GOOD:
-    case INTERMEDIATE_GOOD:
-    case INTERMEDIATE_C_GOOD:
-      /*
-       * Who knows?  FIXME(eric)
-       */
-      return SUCCESS;
-    case BUSY:
-    case RESERVATION_CONFLICT:
-      goto maybe_retry;
-    default:
-      return FAILED;
-    }
-  return FAILED;
-
-maybe_retry:
-
-  if ((++SCpnt->retries) < SCpnt->allowed)
-    {
-      return NEEDS_RETRY;
-    }
-  else
-    {
-      return FAILED;
-    }
-}
-
-/*
- * Function:	scsi_eh_completed_normally
- *
- * Purpose:	Examine a command block that has come back from the low-level
- *		and figure out what to do next.
- *
- * Returns:	SUCCESS		- pass on to upper level.
- *		FAILED		- pass on to error handler thread.
- *		RETRY		- command should be retried.
- *		SOFTERR		- command succeeded, but we need to log
- *				  a soft error.
- *
- * Notes:	This is *ONLY* called when we are examining the status
- *		of commands queued during error recovery.  The main
- *		difference here is that we don't allow for the possibility
- *		of retries here, and we are a lot more restrictive about what
+/*
+ * Function:  scsi_eh_completed_normally
+ *
+ * Purpose:     Examine a command block that has come back from the low-level
+ *              and figure out what to do next.
+ *
+ * Returns:     SUCCESS         - pass on to upper level.
+ *              FAILED          - pass on to error handler thread.
+ *              RETRY           - command should be retried.
+ *              SOFTERR         - command succeeded, but we need to log
+ *                                a soft error.
+ *
+ * Notes:       This is *ONLY* called when we are examining the status
+ *              of commands queued during error recovery.  The main
+ *              difference here is that we don't allow for the possibility
+ *              of retries here, and we are a lot more restrictive about what
  *              we consider acceptable.
  */
-STATIC int scsi_eh_completed_normally (Scsi_Cmnd * SCpnt)
+STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt)
 {
-  int	rtn;
-  /*
-   * First check the host byte, to see if there is anything in there
-   * that would indicate what we need to do.
-   */
-  if( host_byte(SCpnt->result) == DID_RESET )
-    {
-     if (SCpnt->flags & IS_RESETTING )
-       {
-	 /*
-	  * OK, this is normal.  We don't know whether in fact the
-	  * command in question really needs to be rerun or not - 
-	  * if this was the original data command then the answer is yes,
-	  * otherwise we just flag it as success.
-	  */
-	 SCpnt->flags &= ~IS_RESETTING;
-	 return NEEDS_RETRY;
-       }
-
-     /*
-      * Rats.  We are already in the error handler, so we now get to try
-      * and figure out what to do next.  If the sense is valid, we have
-      * a pretty good idea of what to do.  If not, we mark it as failed.
-      */
-     return scsi_check_sense (SCpnt);
-    }
-
-  if(host_byte(SCpnt->result) != DID_OK )
-  {
-      return FAILED;
-  }
-
-  /*
-   * Next, check the message byte.
-   */
-  if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
-    {
-      return FAILED;
-    }
-
-  /*
-   * Now, check the status byte to see if this indicates anything special.
-   */
-  switch (status_byte(SCpnt->result))
-    {
-    case GOOD:
-    case COMMAND_TERMINATED:
-      return SUCCESS;
-    case CHECK_CONDITION:
-      rtn = scsi_check_sense(SCpnt);
-      if( rtn == NEEDS_RETRY )
-	{
-	  return FAILED;
-	}
-      return rtn;
-    case CONDITION_GOOD:
-    case INTERMEDIATE_GOOD:
-    case INTERMEDIATE_C_GOOD:
-      /*
-       * Who knows?  FIXME(eric)
-       */
-      return SUCCESS;
-    case BUSY:
-    case QUEUE_FULL:
-    case RESERVATION_CONFLICT:
-    default:
-      return FAILED;
-    }
-  return FAILED;
-}
-
-/*
- * Function:	scsi_check_sense
+	int rtn;
+	/*
+	 * First check the host byte, to see if there is anything in there
+	 * that would indicate what we need to do.
+	 */
+	if (host_byte(SCpnt->result) == DID_RESET) {
+		if (SCpnt->flags & IS_RESETTING) {
+			/*
+			 * OK, this is normal.  We don't know whether in fact the
+			 * command in question really needs to be rerun or not - 
+			 * if this was the original data command then the answer is yes,
+			 * otherwise we just flag it as success.
+			 */
+			SCpnt->flags &= ~IS_RESETTING;
+			return NEEDS_RETRY;
+		}
+		/*
+		 * Rats.  We are already in the error handler, so we now get to try
+		 * and figure out what to do next.  If the sense is valid, we have
+		 * a pretty good idea of what to do.  If not, we mark it as failed.
+		 */
+		return scsi_check_sense(SCpnt);
+	}
+	if (host_byte(SCpnt->result) != DID_OK) {
+		return FAILED;
+	}
+	/*
+	 * Next, check the message byte.
+	 */
+	if (msg_byte(SCpnt->result) != COMMAND_COMPLETE) {
+		return FAILED;
+	}
+	/*
+	 * Now, check the status byte to see if this indicates anything special.
+	 */
+	switch (status_byte(SCpnt->result)) {
+	case GOOD:
+	case COMMAND_TERMINATED:
+		return SUCCESS;
+	case CHECK_CONDITION:
+		rtn = scsi_check_sense(SCpnt);
+		if (rtn == NEEDS_RETRY) {
+			return FAILED;
+		}
+		return rtn;
+	case CONDITION_GOOD:
+	case INTERMEDIATE_GOOD:
+	case INTERMEDIATE_C_GOOD:
+		/*
+		 * Who knows?  FIXME(eric)
+		 */
+		return SUCCESS;
+	case BUSY:
+	case QUEUE_FULL:
+	case RESERVATION_CONFLICT:
+	default:
+		return FAILED;
+	}
+	return FAILED;
+}
+
+/*
+ * Function:  scsi_check_sense
  *
- * Purpose:	Examine sense information - give suggestion as to what
- *		we should do with it.
+ * Purpose:     Examine sense information - give suggestion as to what
+ *              we should do with it.
  */
-STATIC  int scsi_check_sense (Scsi_Cmnd * SCpnt)
+STATIC int scsi_check_sense(Scsi_Cmnd * SCpnt)
 {
-    if ( !scsi_sense_valid(SCpnt) ) 
-      {
-	return FAILED;
-      }
-
-    if (SCpnt->sense_buffer[2] & 0xe0)
-	return SUCCESS;
-
-    switch (SCpnt->sense_buffer[2] & 0xf)
-    {
-    case NO_SENSE:
-	return SUCCESS;
-    case RECOVERED_ERROR:
-	return /* SOFT_ERROR */ SUCCESS;
-
-    case ABORTED_COMMAND:
-	return NEEDS_RETRY;
-    case NOT_READY:
-    case UNIT_ATTENTION:
-        /*
-         * If we are expecting a CC/UA because of a bus reset that we
-         * performed, treat this just as a retry.  Otherwise this is
-         * information that we should pass up to the upper-level driver
-         * so that we can deal with it there.
-         */
-        if( SCpnt->device->expecting_cc_ua )
-        {
-            SCpnt->device->expecting_cc_ua = 0;
-            return NEEDS_RETRY;
-        }
-	return SUCCESS;
-
-    /* these three are not supported */
-    case COPY_ABORTED:
-    case VOLUME_OVERFLOW:
-    case MISCOMPARE:
-        return SUCCESS;
-
-    case MEDIUM_ERROR:
-	return NEEDS_RETRY;
+	if (!scsi_sense_valid(SCpnt)) {
+		return FAILED;
+	}
+	if (SCpnt->sense_buffer[2] & 0xe0)
+		return SUCCESS;
 
-    case ILLEGAL_REQUEST:
-    case BLANK_CHECK:
-    case DATA_PROTECT:
-    case HARDWARE_ERROR:
-    default:
-	return SUCCESS;
-    }
+	switch (SCpnt->sense_buffer[2] & 0xf) {
+	case NO_SENSE:
+		return SUCCESS;
+	case RECOVERED_ERROR:
+		return /* SOFT_ERROR */ SUCCESS;
+
+	case ABORTED_COMMAND:
+		return NEEDS_RETRY;
+	case NOT_READY:
+	case UNIT_ATTENTION:
+		/*
+		 * If we are expecting a CC/UA because of a bus reset that we
+		 * performed, treat this just as a retry.  Otherwise this is
+		 * information that we should pass up to the upper-level driver
+		 * so that we can deal with it there.
+		 */
+		if (SCpnt->device->expecting_cc_ua) {
+			SCpnt->device->expecting_cc_ua = 0;
+			return NEEDS_RETRY;
+		}
+		return SUCCESS;
+
+		/* these three are not supported */
+	case COPY_ABORTED:
+	case VOLUME_OVERFLOW:
+	case MISCOMPARE:
+		return SUCCESS;
+
+	case MEDIUM_ERROR:
+		return NEEDS_RETRY;
+
+	case ILLEGAL_REQUEST:
+	case BLANK_CHECK:
+	case DATA_PROTECT:
+	case HARDWARE_ERROR:
+	default:
+		return SUCCESS;
+	}
 }
 
 
 /*
- * Function:	scsi_restart_operations
+ * Function:  scsi_restart_operations
  *
- * Purpose:	Restart IO operations to the specified host.
+ * Purpose:     Restart IO operations to the specified host.
  *
- * Arguments:	host  - host that we are restarting
+ * Arguments:   host  - host that we are restarting
  *
- * Returns:	Nothing
+ * Returns:     Nothing
  *
- * Notes:	When we entered the error handler, we blocked all further
- *		I/O to this device.  We need to 'reverse' this process.
+ * Notes:       When we entered the error handler, we blocked all further
+ *              I/O to this device.  We need to 'reverse' this process.
  */
-STATIC void
-scsi_restart_operations(struct Scsi_Host * host)
+STATIC void scsi_restart_operations(struct Scsi_Host *host)
 {
-  Scsi_Device * SDpnt;
+	Scsi_Device *SDpnt;
 
-  /*
-   * Next free up anything directly waiting upon the host.  This will be
-   * requests for character device operations, and also for ioctls to queued
-   * block devices.
-   */
-  SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: Waking up host to restart\n"));
+	/*
+	 * Next free up anything directly waiting upon the host.  This will be
+	 * requests for character device operations, and also for ioctls to queued
+	 * block devices.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(5, printk("scsi_error.c: Waking up host to restart\n"));
 
-   wake_up(&host->host_wait);
+	wake_up(&host->host_wait);
 
-   /*
-    * Finally, block devices need an extra kick in the pants.  This is because
-    * the request queueing mechanism may have queued lots of pending requests
-    * and there won't be a process waiting in a place where we can simply wake
-    * it up.  Thus we simply go through and call the request function to goose
-    * the various top level drivers and get things moving again.
-    */
-   for( SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next )
-     {
-       SCSI_LOG_ERROR_RECOVERY(5,printk("Calling request function to restart things...\n"));
+	/*
+	 * Finally, block devices need an extra kick in the pants.  This is because
+	 * the request queueing mechanism may have queued lots of pending requests
+	 * and there won't be a process waiting in a place where we can simply wake
+	 * it up.  Thus we simply go through and call the request function to goose
+	 * the various top level drivers and get things moving again.
+	 */
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		SCSI_LOG_ERROR_RECOVERY(5, printk("Calling request function to restart things...\n"));
 
-       if( SDpnt->scsi_request_fn != NULL )
-	 (*SDpnt->scsi_request_fn)();
-     }
+		if (SDpnt->scsi_request_fn != NULL)
+			(*SDpnt->scsi_request_fn) ();
+	}
 }
 
 /*
- * Function:	scsi_unjam_host
+ * Function:  scsi_unjam_host
  *
- * Purpose:	Attempt to fix a host which has a command that failed for
- *		some reason.
+ * Purpose:     Attempt to fix a host which has a command that failed for
+ *              some reason.
  *
- * Arguments:	host	- host that needs unjamming.
+ * Arguments:   host    - host that needs unjamming.
  * 
- * Returns:	Nothing
+ * Returns:     Nothing
  *
- * Notes:	When we come in here, we *know* that all commands on the
- *		bus have either completed, failed or timed out.  We also
- *		know that no further commands are being sent to the host,
- *		so things are relatively quiet and we have freedom to
- *		fiddle with things as we wish.
+ * Notes:       When we come in here, we *know* that all commands on the
+ *              bus have either completed, failed or timed out.  We also
+ *              know that no further commands are being sent to the host,
+ *              so things are relatively quiet and we have freedom to
+ *              fiddle with things as we wish.
  *
  * Additional note:  This is only the *default* implementation.  It is possible
- *		for individual drivers to supply their own version of this
- *		function, and if the maintainer wishes to do this, it is
- *		strongly suggested that this function be taken as a template
- *		and modified.  This function was designed to correctly handle
- *		problems for about 95% of the different cases out there, and
- *		it should always provide at least a reasonable amount of error
- *		recovery.
+ *              for individual drivers to supply their own version of this
+ *              function, and if the maintainer wishes to do this, it is
+ *              strongly suggested that this function be taken as a template
+ *              and modified.  This function was designed to correctly handle
+ *              problems for about 95% of the different cases out there, and
+ *              it should always provide at least a reasonable amount of error
+ *              recovery.
  *
  * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
  *              have scsi_finish_command() called for it.  We do all of
  *              the retry stuff here, so when we restart the host after we
  *              return it should have an empty queue.
  */
-STATIC int
-scsi_unjam_host(struct Scsi_Host * host)
+STATIC int scsi_unjam_host(struct Scsi_Host *host)
 {
-  int           devices_failed;
-  int           numfailed;
-  int           ourrtn;
-  int		rtn = FALSE;
-  int		result;
-  Scsi_Cmnd   * SCloop;
-  Scsi_Cmnd   * SCpnt;
-  Scsi_Device * SDpnt;
-  Scsi_Device * SDloop;
-  Scsi_Cmnd   * SCdone;
-  int           timed_out;
-
-  SCdone = NULL;
-
-  /*
-   * First, protect against any sort of race condition.  If any of the outstanding
-   * commands are in states that indicate that we are not yet blocked (i.e. we are
-   * not in a quiet state) then we got woken up in error.  If we ever end up here,
-   * we need to re-examine some of the assumptions.
-   */
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-      {
-          if( SCpnt->state == SCSI_STATE_FAILED 
-              || SCpnt->state == SCSI_STATE_TIMEOUT 
-              || SCpnt->state == SCSI_STATE_INITIALIZING
-              || SCpnt->state == SCSI_STATE_UNUSED)
-          {
-              continue;
-          }
-
-          /*
-           * Rats.  Something is still floating around out there.  This could
-           * be the result of the fact that the upper level drivers are still frobbing
-           * commands that might have succeeded.  There are two outcomes.  One is that
-           * the command block will eventually be freed, and the other one is that
-           * the command will be queued and will be finished along the way.
-           */
-          SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
+	int devices_failed;
+	int numfailed;
+	int ourrtn;
+	int rtn = FALSE;
+	int result;
+	Scsi_Cmnd *SCloop;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+	Scsi_Device *SDloop;
+	Scsi_Cmnd *SCdone;
+	int timed_out;
+
+	SCdone = NULL;
+
+	/*
+	 * First, protect against any sort of race condition.  If any of the outstanding
+	 * commands are in states that indicate that we are not yet blocked (i.e. we are
+	 * not in a quiet state) then we got woken up in error.  If we ever end up here,
+	 * we need to re-examine some of the assumptions.
+	 */
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+			if (SCpnt->state == SCSI_STATE_FAILED
+			    || SCpnt->state == SCSI_STATE_TIMEOUT
+			    || SCpnt->state == SCSI_STATE_INITIALIZING
+			    || SCpnt->state == SCSI_STATE_UNUSED) {
+				continue;
+			}
+			/*
+			 * Rats.  Something is still floating around out there.  This could
+			 * be the result of the fact that the upper level drivers are still frobbing
+			 * commands that might have succeeded.  There are two outcomes.  One is that
+			 * the command block will eventually be freed, and the other one is that
+			 * the command will be queued and will be finished along the way.
+			 */
+			SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
 
 /*
  *        panic("SCSI Error handler woken too early\n");
@@ -1365,572 +1283,486 @@
  * state=SCSI_STATE_INITIALIZING and the driver module cannot be released.
  * (DB, 17 May 1998)
  */
-      }
-  }
+		}
+	}
+
+	/*
+	 * Next, see if we need to request sense information.  if so,
+	 * then get it now, so we have a better idea of what to do.
+	 * FIXME(eric) this has the unfortunate side effect that if a host
+	 * adapter does not automatically request sense information, that we end
+	 * up shutting it down before we request it.  All hosts should be doing this
+	 * anyways, so for now all I have to say is tough noogies if you end up in here.
+	 * On second thought, this is probably a good idea.  We *really* want to give
+	 * authors an incentive to automatically request this.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
 
-  /*
-   * Next, see if we need to request sense information.  if so,
-   * then get it now, so we have a better idea of what to do.
-   * FIXME(eric) this has the unfortunate side effect that if a host
-   * adapter does not automatically request sense information, that we end
-   * up shutting it down before we request it.  All hosts should be doing this
-   * anyways, so for now all I have to say is tough noogies if you end up in here.
-   * On second thought, this is probably a good idea.  We *really* want to give
-   * authors an incentive to automatically request this.
-   */
-  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
-
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-      {
-          if( SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt) )
-          {
-              continue;
-          }
-
-          SCSI_LOG_ERROR_RECOVERY(2,printk("scsi_unjam_host: Requesting sense for %d\n",
-                                           SCpnt->target));
-          rtn = scsi_request_sense(SCpnt);
-          if( rtn != SUCCESS )
-          {
-              continue;
-          }
-
-          SCSI_LOG_ERROR_RECOVERY(3,printk("Sense requested for %p - result %x\n",
-                                           SCpnt, SCpnt->result));
-          SCSI_LOG_ERROR_RECOVERY(3,print_sense("bh",SCpnt));
-                  
-          result = scsi_decide_disposition(SCpnt);
-
-          /*
-           * If the result was normal, then just pass it along to the
-           * upper level.
-           */
-          if( result == SUCCESS )
-          {
-              SCpnt->host->host_failed--;
-              scsi_eh_finish_command(&SCdone, SCpnt);
-          }
-
-          if( result != NEEDS_RETRY )
-          {
-              continue;
-          }
-
-          /* 
-           * We only come in here if we want to retry a
-           * command.  The test to see whether the command
-           * should be retried should be keeping track of the
-           * number of tries, so we don't end up looping, of
-           * course.  
-           */
-          SCpnt->state = NEEDS_RETRY;
-          rtn = scsi_eh_retry_command(SCpnt);
-          if( rtn != SUCCESS )
-          {
-              continue;
-          }
-
-          /*
-           * We eventually hand this one back to the top level.
-           */
-          SCpnt->host->host_failed--;
-          scsi_eh_finish_command(&SCdone, SCpnt);
-      }
-  }
-
-  /*
-   * Go through the list of commands and figure out where we stand and how bad things
-   * really are.
-   */
-  numfailed = 0;
-  timed_out = 0;
-  devices_failed = 0;
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-      unsigned int device_error = 0;
-
-      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-      {
-          if( SCpnt->state == SCSI_STATE_FAILED )
-          {
-              SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d failed\n", 
-                                               SCpnt->target));
-              numfailed++;
-              device_error++;
-          }
-          if( SCpnt->state == SCSI_STATE_TIMEOUT )
-          {
-              SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d timedout\n", 
-                                               SCpnt->target));
-              timed_out++;
-              device_error++;
-          }
-      }
-      if( device_error > 0 )
-      {
-          devices_failed++;
-      }
-  }
-
-  SCSI_LOG_ERROR_RECOVERY(2,printk("Total of %d+%d commands on %d devices require eh work\n", 
-                                   numfailed, timed_out, devices_failed));
-
-  if( host->host_failed == 0 )
-  {
-      ourrtn = TRUE;
-      goto leave;
-  }
-
-
-  /*
-   * Next, try and see whether or not it makes sense to try and abort
-   * the running command.  This only works out to be the case if we have
-   * one command that has timed out.  If the command simply failed, it
-   * makes no sense to try and abort the command, since as far as the
-   * host adapter is concerned, it isn't running.
-   */
-
-  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
-
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-      for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
-      {
-          if( SCloop->state != SCSI_STATE_TIMEOUT )
-          {
-              continue;
-          }
-
-	  rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
-	  if( rtn == SUCCESS )
-          {
-	      rtn = scsi_test_unit_ready(SCloop);
-              
-	      if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
-              {
-		  rtn = scsi_eh_retry_command(SCloop);
-                  
-		  if( rtn == SUCCESS )
-                  {
-                      SCloop->host->host_failed--;
-		      scsi_eh_finish_command(&SCdone,SCloop);
-                  }
-              }
-          }
-      }
-  }
-  
-  /*
-   * If we have corrected all of the problems, then we are done.
-   */
-  if( host->host_failed == 0 )
-  {
-      ourrtn = TRUE;
-      goto leave;
-  }
-
-  /*
-   * Either the abort wasn't appropriate, or it didn't succeed.
-   * Now try a bus device reset.  Still, look to see whether we have
-   * multiple devices that are jammed or not - if we have multiple devices,
-   * it makes no sense to try BUS_DEVICE_RESET - we really would need
-   * to try a BUS_RESET instead.
-   *
-   * Does this make sense - should we try BDR on each device individually?
-   * Yes, definitely.
-   */
-  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
-
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-      for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
-      {
-          if( SCloop->state == SCSI_STATE_FAILED 
-              || SCloop->state == SCSI_STATE_TIMEOUT )
-          {
-              break;
-          }
-      }
-
-      if( SCloop == NULL )
-      {
-          continue;
-      }
-
-      /*
-       * OK, we have a device that is having problems.  Try and send
-       * a bus device reset to it.
-       *
-       * FIXME(eric) - make sure we handle the case where multiple
-       * commands to the same device have failed. They all must
-       * get properly restarted.
-       */
-      rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
-      
-      if( rtn == SUCCESS )
-      {
-	  rtn = scsi_test_unit_ready(SCloop);
-	  
-	  if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
-          {
-	      rtn = scsi_eh_retry_command(SCloop);
-	      
-	      if( rtn == SUCCESS )
-              {
-                  SCloop->host->host_failed--;
-		  scsi_eh_finish_command(&SCdone,SCloop);
-              }
-          }
-      }
-      
-  }
-  
-  if( host->host_failed == 0 )
-  {
-      ourrtn = TRUE;
-      goto leave;
-  }
-
-  /*
-   * If we ended up here, we have serious problems.  The only thing left
-   * to try is a full bus reset.  If someone has grabbed the bus and isn't
-   * letting go, then perhaps this will help.
-   */
-  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard bus reset\n"));
-
-  /* 
-   * We really want to loop over the various channels, and do this on
-   * a channel by channel basis.  We should also check to see if any
-   * of the failed commands are on soft_reset devices, and if so, skip
-   * the reset.  
-   */
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-next_device:
-      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-      {
-          if( SCpnt->state != SCSI_STATE_FAILED 
-              && SCpnt->state != SCSI_STATE_TIMEOUT )
-          {
-              continue;
-          }
-          /*
-           * We have a failed command.  Make sure there are no other failed
-           * commands on the same channel that are timed out and implement a
-           * soft reset.
-           */
-          for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
-          {
-              for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
-              {
-                  if( SCloop->channel != SCpnt->channel )
-                  {
-                      continue;
-                  }
-                  
-                  if( SCloop->state != SCSI_STATE_FAILED 
-                      && SCloop->state != SCSI_STATE_TIMEOUT )
-                  {
-                      continue;
-                  }
-                  
-                  if( SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT )
-                  {
-                      /* 
-                       * If this device uses the soft reset option, and this
-                       * is one of the devices acting up, then our only
-                       * option is to wait a bit, since the command is
-                       * supposedly still running.  
-                       *
-                       * FIXME(eric) - right now we will just end up falling
-                       * through to the 'take device offline' case.
-                       *
-                       * FIXME(eric) - It is possible that the command completed
-                       * *after* the error recovery procedure started, and if this
-                       * is the case, we are worrying about nothing here.
-                       */
-
-                      /*
-                       * Due to the spinlock, we will never get out of this
-                       * loop without a proper wait (DB)
-                       */
-                      scsi_sleep(1 * HZ);
-
-                      goto next_device;
-                  }
-              }
-          }
-
-          /*
-           * We now know that we are able to perform a reset for the
-           * bus that SCpnt points to.  There are no soft-reset devices
-           * with outstanding timed out commands.
-           */
-          rtn = scsi_try_bus_reset(SCpnt);
-          if( rtn == SUCCESS )
-          {
-              for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
-              {
-                  for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
-                  {
-                      if( SCloop->channel != SCpnt->channel )
-                      {
-                          continue;
-                      }
-                      
-                      if( SCloop->state != SCSI_STATE_FAILED 
-                          && SCloop->state != SCSI_STATE_TIMEOUT )
-                      {
-                          continue;
-                      }
-                      
-                      rtn = scsi_test_unit_ready(SCloop);
-                      
-                      if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
-                      {
-                          rtn = scsi_eh_retry_command(SCloop);
-                          
-                          if( rtn == SUCCESS )
-                          {
-                              SCpnt->host->host_failed--;
-                              scsi_eh_finish_command(&SCdone,SCloop);
-                          }
-                      }
-                      
-                      /*
-                       * If the bus reset worked, but we are still unable to
-                       * talk to the device, take it offline.
-                       * FIXME(eric) - is this really the correct thing to do?
-                       */
-                      if( rtn != SUCCESS )
-                      {
-                          SCloop->device->online = FALSE;
-                          SCloop->host->host_failed--;
-                          scsi_eh_finish_command(&SCdone,SCloop);
-                      }
-                  }
-              }
-          }
-      }
-  }
-
-  if( host->host_failed == 0 )
-  {
-      ourrtn = TRUE;
-      goto leave;
-  }
-  /*
-   * If we ended up here, we have serious problems.  The only thing left
-   * to try is a full host reset - perhaps the firmware on the device
-   * crashed, or something like that.
-   *
-   * It is assumed that a succesful host reset will cause *all* information
-   * about the command to be flushed from both the host adapter *and* the
-   * device.
-   *
-   * FIXME(eric) - it isn't clear that devices that implement the soft reset
-   * option can ever be cleared except via cycling the power.  The problem is
-   * that sending the host reset command will cause the host to forget
-   * about the pending command, but the device won't forget.  For now, we
-   * skip the host reset option if any of the failed devices are configured
-   * to use the soft reset option.
-   */
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-next_device2:
-      for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-      {
-          if( SCpnt->state != SCSI_STATE_FAILED 
-              && SCpnt->state != SCSI_STATE_TIMEOUT )
-          {
-              continue;
-          }
-          if( SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT )
-          {
-              /* 
-               * If this device uses the soft reset option, and this
-               * is one of the devices acting up, then our only
-               * option is to wait a bit, since the command is
-               * supposedly still running.  
-               *
-               * FIXME(eric) - right now we will just end up falling
-               * through to the 'take device offline' case.
-               */
-              SCSI_LOG_ERROR_RECOVERY(3,
-                        printk("scsi_unjam_host: Unable to try hard host reset\n"));
-
-               /*
-                * Due to the spinlock, we will never get out of this
-                * loop without a proper wait. (DB)
-                */
-               scsi_sleep(1 * HZ);
-
-              goto next_device2;
-          }
-
-          SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard host reset\n"));
-
-          /*
-           * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
-           */
-          rtn = scsi_try_host_reset(SCpnt);
-          if( rtn == SUCCESS )
-          {
-              /*
-               * FIXME(eric) we assume that all commands are flushed from the
-               * controller.  We should get a DID_RESET for all of the commands
-               * that were pending.  We should ignore these so that we can
-               * guarantee that we are in a consistent state.
-               *
-               * I believe this to be the case right now, but this needs to be
-               * tested.
-               */
-            for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
-              {
-                  for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
-                  {
-                      if( SCloop->state != SCSI_STATE_FAILED 
-                          && SCloop->state != SCSI_STATE_TIMEOUT )
-                      {
-                          continue;
-                      }
-                      
-                      rtn = scsi_test_unit_ready(SCloop);
-                      
-                      if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
-                      {
-                          rtn = scsi_eh_retry_command(SCloop);
-                          
-                          if( rtn == SUCCESS )
-                          {
-                              SCpnt->host->host_failed--;
-                              scsi_eh_finish_command(&SCdone,SCloop);
-                          }
-                      }
-                      if( rtn != SUCCESS )
-                      {
-                          SCloop->device->online = FALSE;
-                          SCloop->host->host_failed--;
-                          scsi_eh_finish_command(&SCdone,SCloop);
-                      }
-                  }
-              }
-          }
-      }
-  }
-
-  /*
-   * If we solved all of the problems, then let's rev up the engines again.
-   */
-  if( host->host_failed == 0 )
-  {
-      ourrtn = TRUE;
-      goto leave;
-  }
-
-  /*
-   * If the HOST RESET failed, then for now we assume that the entire host
-   * adapter is too hosed to be of any use.  For our purposes, however, it is
-   * easier to simply take the devices offline that correspond to commands
-   * that failed.
-   */
-  SCSI_LOG_ERROR_RECOVERY(1,printk("scsi_unjam_host: Take device offline\n"));
-
-  for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
-  {
-      for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
-      {
-          if( SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT )
-          {
-              SCloop->device->online = FALSE;
-              
-              /*
-               * This should pass the failure up to the top level driver, and
-               * it will have to try and do something intelligent with it.
-               */
-              SCloop->host->host_failed--;
-              
-              if( SCloop->state == SCSI_STATE_TIMEOUT )
-              {
-                  SCloop->result |= (DRIVER_TIMEOUT << 24);
-              }
-
-              SCSI_LOG_ERROR_RECOVERY(3,printk("Finishing command for device %d %x\n",
-                     SCloop->device->id, SCloop->result));
-              
-              scsi_eh_finish_command(&SCdone,SCloop);
-          }
-      }
-  }
-
-  if( host->host_failed != 0 )
-  {
-      panic("scsi_unjam_host: Miscount of number of failed commands.\n");
-  }
-
-  SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Returning\n"));
-
-  ourrtn = FALSE;
-
-leave:
-
-  /*
-   * We should have a list of commands that we 'finished' during the course of
-   * error recovery.  This should be the same as the list of commands that timed out
-   * or failed.  We are currently holding these things in a linked list - we didn't
-   * put them in the bottom half queue because we wanted to keep things quiet while
-   * we were working on recovery, and passing them up to the top level could easily
-   * cause the top level to try and queue something else again.
-   *
-   * Start by marking that the host is no longer in error recovery.
-   */
-  host->in_recovery = 0;
-
-  /*
-   * Take the list of commands, and stick them in the bottom half queue.
-   * The current implementation of scsi_done will do this for us - if need
-   * be we can create a special version of this function to do the
-   * same job for us.
-   */
-  for(SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone)
-  {
-      SCdone = SCpnt->bh_next;
-      SCpnt->bh_next = NULL;
-      scsi_done(SCpnt);
-  }
-
-  return (ourrtn);
-}
-
-
-/*
- * Function:	scsi_error_handler
- *
- * Purpose:	Handle errors/timeouts of scsi commands, try and clean up
- *		and unjam the bus, and restart things.
- *
- * Arguments:	host	- host for which we are running.
- *
- * Returns:	Never returns.
- *
- * Notes:	This is always run in the context of a kernel thread.  The
- *		idea is that we start this thing up when the kernel starts
- *		up (one per host that we detect), and it immediately goes to
- *		sleep and waits for some event (i.e. failure).  When this
- *		takes place, we have the job of trying to unjam the bus
- *		and restarting things.
- *
- */
-void
-scsi_error_handler(void * data)
-{
-	struct Scsi_Host     * host = (struct Scsi_Host *) data;
-	int	               rtn;
-        DECLARE_MUTEX_LOCKED(sem);
-        unsigned long flags;
-        struct fs_struct *fs;
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+			if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt)) {
+				continue;
+			}
+			SCSI_LOG_ERROR_RECOVERY(2, printk("scsi_unjam_host: Requesting sense for %d\n",
+							  SCpnt->target));
+			rtn = scsi_request_sense(SCpnt);
+			if (rtn != SUCCESS) {
+				continue;
+			}
+			SCSI_LOG_ERROR_RECOVERY(3, printk("Sense requested for %p - result %x\n",
+						  SCpnt, SCpnt->result));
+			SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", SCpnt));
+
+			result = scsi_decide_disposition(SCpnt);
+
+			/*
+			 * If the result was normal, then just pass it along to the
+			 * upper level.
+			 */
+			if (result == SUCCESS) {
+				SCpnt->host->host_failed--;
+				scsi_eh_finish_command(&SCdone, SCpnt);
+			}
+			if (result != NEEDS_RETRY) {
+				continue;
+			}
+			/* 
+			 * We only come in here if we want to retry a
+			 * command.  The test to see whether the command
+			 * should be retried should be keeping track of the
+			 * number of tries, so we don't end up looping, of
+			 * course.  
+			 */
+			SCpnt->state = NEEDS_RETRY;
+			rtn = scsi_eh_retry_command(SCpnt);
+			if (rtn != SUCCESS) {
+				continue;
+			}
+			/*
+			 * We eventually hand this one back to the top level.
+			 */
+			SCpnt->host->host_failed--;
+			scsi_eh_finish_command(&SCdone, SCpnt);
+		}
+	}
+
+	/*
+	 * Go through the list of commands and figure out where we stand and how bad things
+	 * really are.
+	 */
+	numfailed = 0;
+	timed_out = 0;
+	devices_failed = 0;
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		unsigned int device_error = 0;
+
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+			if (SCpnt->state == SCSI_STATE_FAILED) {
+				SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d failed\n",
+							 SCpnt->target));
+				numfailed++;
+				device_error++;
+			}
+			if (SCpnt->state == SCSI_STATE_TIMEOUT) {
+				SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d timedout\n",
+							 SCpnt->target));
+				timed_out++;
+				device_error++;
+			}
+		}
+		if (device_error > 0) {
+			devices_failed++;
+		}
+	}
+
+	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d+%d commands on %d devices require eh work\n",
+				  numfailed, timed_out, devices_failed));
+
+	if (host->host_failed == 0) {
+		ourrtn = TRUE;
+		goto leave;
+	}
+	/*
+	 * Next, try and see whether or not it makes sense to try and abort
+	 * the running command.  This only works out to be the case if we have
+	 * one command that has timed out.  If the command simply failed, it
+	 * makes no sense to try and abort the command, since as far as the
+	 * host adapter is concerned, it isn't running.
+	 */
+
+	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
+
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
+			if (SCloop->state != SCSI_STATE_TIMEOUT) {
+				continue;
+			}
+			rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
+			if (rtn == SUCCESS) {
+				rtn = scsi_test_unit_ready(SCloop);
+
+				if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+					rtn = scsi_eh_retry_command(SCloop);
+
+					if (rtn == SUCCESS) {
+						SCloop->host->host_failed--;
+						scsi_eh_finish_command(&SCdone, SCloop);
+					}
+				}
+			}
+		}
+	}
+
+	/*
+	 * If we have corrected all of the problems, then we are done.
+	 */
+	if (host->host_failed == 0) {
+		ourrtn = TRUE;
+		goto leave;
+	}
+	/*
+	 * Either the abort wasn't appropriate, or it didn't succeed.
+	 * Now try a bus device reset.  Still, look to see whether we have
+	 * multiple devices that are jammed or not - if we have multiple devices,
+	 * it makes no sense to try BUS_DEVICE_RESET - we really would need
+	 * to try a BUS_RESET instead.
+	 *
+	 * Does this make sense - should we try BDR on each device individually?
+	 * Yes, definitely.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
+
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
+			if (SCloop->state == SCSI_STATE_FAILED
+			    || SCloop->state == SCSI_STATE_TIMEOUT) {
+				break;
+			}
+		}
+
+		if (SCloop == NULL) {
+			continue;
+		}
+		/*
+		 * OK, we have a device that is having problems.  Try and send
+		 * a bus device reset to it.
+		 *
+		 * FIXME(eric) - make sure we handle the case where multiple
+		 * commands to the same device have failed. They all must
+		 * get properly restarted.
+		 */
+		rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
+
+		if (rtn == SUCCESS) {
+			rtn = scsi_test_unit_ready(SCloop);
+
+			if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+				rtn = scsi_eh_retry_command(SCloop);
+
+				if (rtn == SUCCESS) {
+					SCloop->host->host_failed--;
+					scsi_eh_finish_command(&SCdone, SCloop);
+				}
+			}
+		}
+	}
+
+	if (host->host_failed == 0) {
+		ourrtn = TRUE;
+		goto leave;
+	}
+	/*
+	 * If we ended up here, we have serious problems.  The only thing left
+	 * to try is a full bus reset.  If someone has grabbed the bus and isn't
+	 * letting go, then perhaps this will help.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard bus reset\n"));
+
+	/* 
+	 * We really want to loop over the various channels, and do this on
+	 * a channel by channel basis.  We should also check to see if any
+	 * of the failed commands are on soft_reset devices, and if so, skip
+	 * the reset.  
+	 */
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+	      next_device:
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+			if (SCpnt->state != SCSI_STATE_FAILED
+			    && SCpnt->state != SCSI_STATE_TIMEOUT) {
+				continue;
+			}
+			/*
+			 * We have a failed command.  Make sure there are no other failed
+			 * commands on the same channel that are timed out and implement a
+			 * soft reset.
+			 */
+			for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
+				for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
+					if (SCloop->channel != SCpnt->channel) {
+						continue;
+					}
+					if (SCloop->state != SCSI_STATE_FAILED
+					    && SCloop->state != SCSI_STATE_TIMEOUT) {
+						continue;
+					}
+					if (SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT) {
+						/* 
+						 * If this device uses the soft reset option, and this
+						 * is one of the devices acting up, then our only
+						 * option is to wait a bit, since the command is
+						 * supposedly still running.  
+						 *
+						 * FIXME(eric) - right now we will just end up falling
+						 * through to the 'take device offline' case.
+						 *
+						 * FIXME(eric) - It is possible that the command completed
+						 * *after* the error recovery procedure started, and if this
+						 * is the case, we are worrying about nothing here.
+						 */
+
+						/*
+						 * Due to the spinlock, we will never get out of this
+						 * loop without a proper wait (DB)
+						 */
+						scsi_sleep(1 * HZ);
+
+						goto next_device;
+					}
+				}
+			}
+
+			/*
+			 * We now know that we are able to perform a reset for the
+			 * bus that SCpnt points to.  There are no soft-reset devices
+			 * with outstanding timed out commands.
+			 */
+			rtn = scsi_try_bus_reset(SCpnt);
+			if (rtn == SUCCESS) {
+				for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
+					for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
+						if (SCloop->channel != SCpnt->channel) {
+							continue;
+						}
+						if (SCloop->state != SCSI_STATE_FAILED
+						    && SCloop->state != SCSI_STATE_TIMEOUT) {
+							continue;
+						}
+						rtn = scsi_test_unit_ready(SCloop);
+
+						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+							rtn = scsi_eh_retry_command(SCloop);
+
+							if (rtn == SUCCESS) {
+								SCpnt->host->host_failed--;
+								scsi_eh_finish_command(&SCdone, SCloop);
+							}
+						}
+						/*
+						 * If the bus reset worked, but we are still unable to
+						 * talk to the device, take it offline.
+						 * FIXME(eric) - is this really the correct thing to do?
+						 */
+						if (rtn != SUCCESS) {
+							SCloop->device->online = FALSE;
+							SCloop->host->host_failed--;
+							scsi_eh_finish_command(&SCdone, SCloop);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (host->host_failed == 0) {
+		ourrtn = TRUE;
+		goto leave;
+	}
+	/*
+	 * If we ended up here, we have serious problems.  The only thing left
+	 * to try is a full host reset - perhaps the firmware on the device
+	 * crashed, or something like that.
+	 *
+	 * It is assumed that a succesful host reset will cause *all* information
+	 * about the command to be flushed from both the host adapter *and* the
+	 * device.
+	 *
+	 * FIXME(eric) - it isn't clear that devices that implement the soft reset
+	 * option can ever be cleared except via cycling the power.  The problem is
+	 * that sending the host reset command will cause the host to forget
+	 * about the pending command, but the device won't forget.  For now, we
+	 * skip the host reset option if any of the failed devices are configured
+	 * to use the soft reset option.
+	 */
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+	      next_device2:
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+			if (SCpnt->state != SCSI_STATE_FAILED
+			    && SCpnt->state != SCSI_STATE_TIMEOUT) {
+				continue;
+			}
+			if (SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT) {
+				/* 
+				 * If this device uses the soft reset option, and this
+				 * is one of the devices acting up, then our only
+				 * option is to wait a bit, since the command is
+				 * supposedly still running.  
+				 *
+				 * FIXME(eric) - right now we will just end up falling
+				 * through to the 'take device offline' case.
+				 */
+				SCSI_LOG_ERROR_RECOVERY(3,
+							printk("scsi_unjam_host: Unable to try hard host reset\n"));
+
+				/*
+				 * Due to the spinlock, we will never get out of this
+				 * loop without a proper wait. (DB)
+				 */
+				scsi_sleep(1 * HZ);
+
+				goto next_device2;
+			}
+			SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard host reset\n"));
+
+			/*
+			 * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
+			 */
+			rtn = scsi_try_host_reset(SCpnt);
+			if (rtn == SUCCESS) {
+				/*
+				 * FIXME(eric) we assume that all commands are flushed from the
+				 * controller.  We should get a DID_RESET for all of the commands
+				 * that were pending.  We should ignore these so that we can
+				 * guarantee that we are in a consistent state.
+				 *
+				 * I believe this to be the case right now, but this needs to be
+				 * tested.
+				 */
+				for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
+					for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
+						if (SCloop->state != SCSI_STATE_FAILED
+						    && SCloop->state != SCSI_STATE_TIMEOUT) {
+							continue;
+						}
+						rtn = scsi_test_unit_ready(SCloop);
+
+						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+							rtn = scsi_eh_retry_command(SCloop);
+
+							if (rtn == SUCCESS) {
+								SCpnt->host->host_failed--;
+								scsi_eh_finish_command(&SCdone, SCloop);
+							}
+						}
+						if (rtn != SUCCESS) {
+							SCloop->device->online = FALSE;
+							SCloop->host->host_failed--;
+							scsi_eh_finish_command(&SCdone, SCloop);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/*
+	 * If we solved all of the problems, then let's rev up the engines again.
+	 */
+	if (host->host_failed == 0) {
+		ourrtn = TRUE;
+		goto leave;
+	}
+	/*
+	 * If the HOST RESET failed, then for now we assume that the entire host
+	 * adapter is too hosed to be of any use.  For our purposes, however, it is
+	 * easier to simply take the devices offline that correspond to commands
+	 * that failed.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(1, printk("scsi_unjam_host: Take device offline\n"));
+
+	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
+			if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) {
+				SCloop->device->online = FALSE;
+
+				/*
+				 * This should pass the failure up to the top level driver, and
+				 * it will have to try and do something intelligent with it.
+				 */
+				SCloop->host->host_failed--;
+
+				if (SCloop->state == SCSI_STATE_TIMEOUT) {
+					SCloop->result |= (DRIVER_TIMEOUT << 24);
+				}
+				SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n",
+				    SCloop->device->id, SCloop->result));
+
+				scsi_eh_finish_command(&SCdone, SCloop);
+			}
+		}
+	}
+
+	if (host->host_failed != 0) {
+		panic("scsi_unjam_host: Miscount of number of failed commands.\n");
+	}
+	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Returning\n"));
+
+	ourrtn = FALSE;
+
+      leave:
+
+	/*
+	 * We should have a list of commands that we 'finished' during the course of
+	 * error recovery.  This should be the same as the list of commands that timed out
+	 * or failed.  We are currently holding these things in a linked list - we didn't
+	 * put them in the bottom half queue because we wanted to keep things quiet while
+	 * we were working on recovery, and passing them up to the top level could easily
+	 * cause the top level to try and queue something else again.
+	 *
+	 * Start by marking that the host is no longer in error recovery.
+	 */
+	host->in_recovery = 0;
+
+	/*
+	 * Take the list of commands, and stick them in the bottom half queue.
+	 * The current implementation of scsi_done will do this for us - if need
+	 * be we can create a special version of this function to do the
+	 * same job for us.
+	 */
+	for (SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone) {
+		SCdone = SCpnt->bh_next;
+		SCpnt->bh_next = NULL;
+		scsi_done(SCpnt);
+	}
+
+	return (ourrtn);
+}
+
+
+/*
+ * Function:  scsi_error_handler
+ *
+ * Purpose:     Handle errors/timeouts of scsi commands, try and clean up
+ *              and unjam the bus, and restart things.
+ *
+ * Arguments:   host    - host for which we are running.
+ *
+ * Returns:     Never returns.
+ *
+ * Notes:       This is always run in the context of a kernel thread.  The
+ *              idea is that we start this thing up when the kernel starts
+ *              up (one per host that we detect), and it immediately goes to
+ *              sleep and waits for some event (i.e. failure).  When this
+ *              takes place, we have the job of trying to unjam the bus
+ *              and restarting things.
+ *
+ */
+void scsi_error_handler(void *data)
+{
+	struct Scsi_Host *host = (struct Scsi_Host *) data;
+	int rtn;
+	DECLARE_MUTEX_LOCKED(sem);
+	unsigned long flags;
+	struct fs_struct *fs;
 
 	lock_kernel();
 
@@ -1943,9 +1775,9 @@
 
 	current->session = 1;
 	current->pgrp = 1;
-	
+
 	/* Become as one with the init task */
-	
+
 	exit_fs(current);	/* current->fs->count--; */
 	fs = init_task.fs;
 	current->fs = fs;
@@ -1961,64 +1793,60 @@
 
 	host->eh_wait = &sem;
 	host->ehandler = current;
-        
+
 	unlock_kernel();
 
-        /*
-         * Wake up the thread that created us.
-         */
-        SCSI_LOG_ERROR_RECOVERY(3,printk("Wake up parent %d\n", host->eh_notify->count.counter));
-
-        up(host->eh_notify);
-
-	while(1)
-	  {
-	    /*
-	     * If we get a signal, it means we are supposed to go
-	     * away and die.  This typically happens if the user is
-	     * trying to unload a module.
-	     */
-            SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler sleeping\n"));
-	    down_interruptible (&sem);
-
-	    if (signal_pending(current) )
-	      break;
-
-            SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler waking up\n"));
-
-	    spin_lock_irqsave(&io_request_lock, flags);
-            host->eh_active = 1;
-
-	    /*
-	     * We have a host that is failing for some reason.  Figure out
-	     * what we need to do to get it up and online again (if we can).
-	     * If we fail, we end up taking the thing offline.
-	     */
-	    if( host->hostt->eh_strategy_handler != NULL )
-	      {
-		rtn = host->hostt->eh_strategy_handler(host);
-	      }
-	    else
-	      {
-		rtn = scsi_unjam_host(host);
-	      }
-
-            host->eh_active = 0;
-
-	    /*
-	     * Note - if the above fails completely, the action is to take
-	     * individual devices offline and flush the queue of any
-	     * outstanding requests that may have been pending.  When we
-	     * restart, we restart any I/O to any other devices on the bus
-	     * which are still online.
-	     */
-	    scsi_restart_operations(host);
- 
-            /* The spinlock is really needed up to this point. (DB) */
-	    spin_unlock_irqrestore(&io_request_lock, flags);
-	  }
+	/*
+	 * Wake up the thread that created us.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent %d\n", host->eh_notify->count.counter));
+
+	up(host->eh_notify);
+
+	while (1) {
+		/*
+		 * If we get a signal, it means we are supposed to go
+		 * away and die.  This typically happens if the user is
+		 * trying to unload a module.
+		 */
+		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler sleeping\n"));
+		down_interruptible(&sem);
+
+		if (signal_pending(current))
+			break;
+
+		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler waking up\n"));
+
+		spin_lock_irqsave(&io_request_lock, flags);
+		host->eh_active = 1;
+
+		/*
+		 * We have a host that is failing for some reason.  Figure out
+		 * what we need to do to get it up and online again (if we can).
+		 * If we fail, we end up taking the thing offline.
+		 */
+		if (host->hostt->eh_strategy_handler != NULL) {
+			rtn = host->hostt->eh_strategy_handler(host);
+		} else {
+			rtn = scsi_unjam_host(host);
+		}
+
+		host->eh_active = 0;
+
+		/*
+		 * Note - if the above fails completely, the action is to take
+		 * individual devices offline and flush the queue of any
+		 * outstanding requests that may have been pending.  When we
+		 * restart, we restart any I/O to any other devices on the bus
+		 * which are still online.
+		 */
+		scsi_restart_operations(host);
+
+		/* The spinlock is really needed up to this point. (DB) */
+		spin_unlock_irqrestore(&io_request_lock, flags);
+	}
 
-        SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler exiting\n"));
+	SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler exiting\n"));
 
 	/*
 	 * Make sure that nobody tries to wake us up again.
@@ -2032,7 +1860,7 @@
 	 * potentially in real danger.
 	 */
 	host->in_recovery = 0;
-        host->eh_active = 0;
+	host->eh_active = 0;
 	host->ehandler = NULL;
 
 	/*
@@ -2043,8 +1871,8 @@
 	 * the error handling thread wakes up that it would just exit without
 	 * needing to touch any memory associated with the driver itself.
 	 */
-	if( host->eh_notify != NULL )
-	  up(host->eh_notify);
+	if (host->eh_notify != NULL)
+		up(host->eh_notify);
 }
 
 /*
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.3.16/linux/drivers/scsi/scsi_ioctl.c	Tue May 11 14:37:40 1999
+++ linux/drivers/scsi/scsi_ioctl.c	Sat Sep  4 10:48:46 1999
@@ -18,12 +18,12 @@
 #include "hosts.h"
 #include <scsi/scsi_ioctl.h>
 
-#define NORMAL_RETRIES 5   
-#define NORMAL_TIMEOUT (10 * HZ)
-#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
-#define START_STOP_TIMEOUT (60 * HZ)
-#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
-#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
+#define NORMAL_RETRIES			5
+#define NORMAL_TIMEOUT			(10 * HZ)
+#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
+#define START_STOP_TIMEOUT		(60 * HZ)
+#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
+#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
 
 #define MAX_BUF PAGE_SIZE
 
@@ -36,36 +36,38 @@
  * (int *) arg
  */
 
-static int ioctl_probe(struct Scsi_Host * host, void *buffer)
+static int ioctl_probe(struct Scsi_Host *host, void *buffer)
 {
-    int temp, result;
-    unsigned int len,slen;
-    const char * string;
-    
-    if ((temp = host->hostt->present) && buffer) {
-        result = verify_area(VERIFY_READ, buffer, sizeof(long));
-        if (result) return result;
-
-	get_user(len, (unsigned int *) buffer);
-	if(host->hostt->info)
-	    string = host->hostt->info(host);
-	else 
-	    string = host->hostt->name;
-	if(string) {
-	    slen = strlen(string);
-	    if (len > slen)
-		len = slen + 1;
-            result = verify_area(VERIFY_WRITE, buffer, len);
-            if (result) return result;
+	int temp, result;
+	unsigned int len, slen;
+	const char *string;
+
+	if ((temp = host->hostt->present) && buffer) {
+		result = verify_area(VERIFY_READ, buffer, sizeof(long));
+		if (result)
+			return result;
+
+		get_user(len, (unsigned int *) buffer);
+		if (host->hostt->info)
+			string = host->hostt->info(host);
+		else
+			string = host->hostt->name;
+		if (string) {
+			slen = strlen(string);
+			if (len > slen)
+				len = slen + 1;
+			result = verify_area(VERIFY_WRITE, buffer, len);
+			if (result)
+				return result;
 
-	    copy_to_user (buffer, string, len);
+			copy_to_user(buffer, string, len);
+		}
 	}
-    }
-    return temp;
+	return temp;
 }
 
 /*
- * 
+
  * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
  * The NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.  
  * 
@@ -88,87 +90,89 @@
  * The output area is then filled in starting from the command byte. 
  */
 
-static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
+static void scsi_ioctl_done(Scsi_Cmnd * SCpnt)
 {
-    struct request * req;
-    
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
-    
-    if (req->sem != NULL) {
-	up(req->sem);
-    }
-}   
+	struct request *req;
+
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	if (req->sem != NULL) {
+		up(req->sem);
+	}
+}
 
-static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
+static int ioctl_internal_command(Scsi_Device * dev, char *cmd,
 				  int timeout, int retries)
 {
-    unsigned long flags;
-    int result;
-    Scsi_Cmnd * SCpnt;
-    Scsi_Device * SDpnt;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-
-    SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
-    SCpnt = scsi_allocate_device(NULL, dev, 1);
-    {
-	DECLARE_MUTEX_LOCKED(sem);
-	SCpnt->request.sem = &sem;
-	scsi_do_cmd(SCpnt,  cmd, NULL,  0, scsi_ioctl_done,  timeout, retries);
+	unsigned long flags;
+	int result;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
+	SCpnt = scsi_allocate_device(NULL, dev, 1);
+	{
+		DECLARE_MUTEX_LOCKED(sem);
+		SCpnt->request.sem = &sem;
+		scsi_do_cmd(SCpnt, cmd, NULL, 0, scsi_ioctl_done, timeout, retries);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		down(&sem);
+		spin_lock_irqsave(&io_request_lock, flags);
+		SCpnt->request.sem = NULL;
+	}
+
+	SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
+
+	if (driver_byte(SCpnt->result) != 0)
+		switch (SCpnt->sense_buffer[2] & 0xf) {
+		case ILLEGAL_REQUEST:
+			if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
+				dev->lockable = 0;
+			else
+				printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
+			break;
+		case NOT_READY:	/* This happens if there is no disc in drive */
+			if (dev->removable && (cmd[0] != TEST_UNIT_READY)) {
+				printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
+				break;
+			}
+		case UNIT_ATTENTION:
+			if (dev->removable) {
+				dev->changed = 1;
+				SCpnt->result = 0;	/* This is no longer considered an error */
+				/* gag this error, VFS will log it anyway /axboe */
+				/* printk(KERN_INFO "Disc change detected.\n"); */
+				break;
+			};
+		default:	/* Fall through for non-removable media */
+			printk("SCSI error: host %d id %d lun %d return code = %x\n",
+			       dev->host->host_no,
+			       dev->id,
+			       dev->lun,
+			       SCpnt->result);
+			printk("\tSense class %x, sense error %x, extended sense %x\n",
+			       sense_class(SCpnt->sense_buffer[0]),
+			       sense_error(SCpnt->sense_buffer[0]),
+			       SCpnt->sense_buffer[2] & 0xf);
+
+		};
+
+	result = SCpnt->result;
+
+	SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+		(*SDpnt->scsi_request_fn) ();
+
+	wake_up(&SDpnt->device_wait);
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	down(&sem);
-        spin_lock_irqsave(&io_request_lock, flags);
-        SCpnt->request.sem = NULL;
-    }
-    
-    SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", SCpnt->result));
-
-    if(driver_byte(SCpnt->result) != 0)
-	switch(SCpnt->sense_buffer[2] & 0xf) {
-	case ILLEGAL_REQUEST:
-	    if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
-	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
-	    break;
-	case NOT_READY: /* This happens if there is no disc in drive */
-	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
-		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
-		break;
-	    }
-	case UNIT_ATTENTION:
-	    if (dev->removable){
-		dev->changed = 1;
-		SCpnt->result = 0; /* This is no longer considered an error */
-		/* gag this error, VFS will log it anyway /axboe */
-		/* printk(KERN_INFO "Disc change detected.\n"); */
-		break;
-	    };
-	default: /* Fall through for non-removable media */
-	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
-		   dev->host->host_no,
-		   dev->id,
-		   dev->lun,
-		   SCpnt->result);
-	    printk("\tSense class %x, sense error %x, extended sense %x\n",
-		   sense_class(SCpnt->sense_buffer[0]),
-		   sense_error(SCpnt->sense_buffer[0]),
-		   SCpnt->sense_buffer[2] & 0xf);
-	    
-	};
-    
-    result = SCpnt->result;
-
-    SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
-    SDpnt = SCpnt->device;
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-	(*SDpnt->scsi_request_fn)();
-
-    wake_up(&SDpnt->device_wait);
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return result;
+	return result;
 }
 
 /*
@@ -176,175 +180,183 @@
  * interface instead, as this is a more flexible approach to performing
  * generic SCSI commands on a device.
  */
-int scsi_ioctl_send_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
+int scsi_ioctl_send_command(Scsi_Device * dev, Scsi_Ioctl_Command * sic)
 {
-    unsigned long flags;
-    char * buf;
-    unsigned char cmd[12]; 
-    char * cmd_in;
-    Scsi_Cmnd * SCpnt;
-    Scsi_Device * SDpnt;
-    unsigned char opcode;
-    int inlen, outlen, cmdlen;
-    int needed, buf_needed;
-    int timeout, retries, result;
-    
-    if (!sic)
-	return -EINVAL;
-    
-
-    /*
-     * Verify that we can read at least this much.
-     */
-    result = verify_area(VERIFY_READ, sic, sizeof (Scsi_Ioctl_Command));
-    if (result) return result;
-
-    /*
-     * The structure that we are passed should look like:
-     *
-     * struct sdata {
-     *	unsigned int inlen;
-     *	unsigned int outlen;
-     *	unsigned char  cmd[];  # However many bytes are used for cmd.
-     *	unsigned char  data[];
-     * };
-     */
-    get_user(inlen, &sic->inlen);
-    get_user(outlen, &sic->outlen);
-    
-    /*
-     * We do not transfer more than MAX_BUF with this interface.
-     * If the user needs to transfer more data than this, they
-     * should use scsi_generics instead.
-     */
-    if( inlen > MAX_BUF ) return -EINVAL;
-    if( outlen > MAX_BUF ) return -EINVAL;
-
-    cmd_in = sic->data;
-    get_user(opcode, cmd_in); 
-    
-    needed = buf_needed = (inlen > outlen ? inlen : outlen);
-    if(buf_needed){
-	buf_needed = (buf_needed + 511) & ~511;
-	if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
-        spin_lock_irqsave(&io_request_lock, flags);
-	buf = (char *) scsi_malloc(buf_needed);
-        spin_unlock_irqrestore(&io_request_lock, flags);
-	if (!buf) return -ENOMEM;
-	memset(buf, 0, buf_needed);
-    } else
-	buf = NULL;
-    
-    /*
-     * Obtain the command from the user's address space.
-     */
-    cmdlen = COMMAND_SIZE(opcode);
-
-    result = verify_area(VERIFY_READ, cmd_in, 
-                         cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
-    if (result) return result;
-
-    copy_from_user ((void *) cmd,  cmd_in,  cmdlen);
-    
-    /*
-     * Obtain the data to be sent to the device (if any).
-     */
-    copy_from_user ((void *) buf,  
-                   (void *) (cmd_in + cmdlen), 
-                   inlen);
-    
-    /*
-     * Set the lun field to the correct value.
-     */
-    cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
-    
-    switch (opcode)
-      {
-      case FORMAT_UNIT:
- 	timeout = FORMAT_UNIT_TIMEOUT;
-	retries = 1;
-	break;
-      case START_STOP:
- 	timeout = START_STOP_TIMEOUT;
- 	retries = NORMAL_RETRIES;
-	break;
-      case MOVE_MEDIUM:
- 	timeout = MOVE_MEDIUM_TIMEOUT;
- 	retries = NORMAL_RETRIES;
- 	break;
-      case READ_ELEMENT_STATUS:
- 	timeout = READ_ELEMENT_STATUS_TIMEOUT;
- 	retries = NORMAL_RETRIES;
-	break;
-      default:
- 	timeout = NORMAL_TIMEOUT;
- 	retries = NORMAL_RETRIES;
-	break;
-      }
+	unsigned long flags;
+	char *buf;
+	unsigned char cmd[12];
+	char *cmd_in;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
+	unsigned char opcode;
+	int inlen, outlen, cmdlen;
+	int needed, buf_needed;
+	int timeout, retries, result;
+
+	if (!sic)
+		return -EINVAL;
+
+
+	/*
+	 * Verify that we can read at least this much.
+	 */
+	result = verify_area(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command));
+	if (result)
+		return result;
+
+	/*
+	 * The structure that we are passed should look like:
+	 *
+	 * struct sdata {
+	 *  unsigned int inlen;
+	 *  unsigned int outlen;
+	 *  unsigned char  cmd[];  # However many bytes are used for cmd.
+	 *  unsigned char  data[];
+	 * };
+	 */
+	get_user(inlen, &sic->inlen);
+	get_user(outlen, &sic->outlen);
+
+	/*
+	 * We do not transfer more than MAX_BUF with this interface.
+	 * If the user needs to transfer more data than this, they
+	 * should use scsi_generics instead.
+	 */
+	if (inlen > MAX_BUF)
+		return -EINVAL;
+	if (outlen > MAX_BUF)
+		return -EINVAL;
+
+	cmd_in = sic->data;
+	get_user(opcode, cmd_in);
+
+	needed = buf_needed = (inlen > outlen ? inlen : outlen);
+	if (buf_needed) {
+		buf_needed = (buf_needed + 511) & ~511;
+		if (buf_needed > MAX_BUF)
+			buf_needed = MAX_BUF;
+		spin_lock_irqsave(&io_request_lock, flags);
+		buf = (char *) scsi_malloc(buf_needed);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		if (!buf)
+			return -ENOMEM;
+		memset(buf, 0, buf_needed);
+	} else
+		buf = NULL;
+
+	/*
+	 * Obtain the command from the user's address space.
+	 */
+	cmdlen = COMMAND_SIZE(opcode);
+
+	result = verify_area(VERIFY_READ, cmd_in,
+		    cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
+	if (result)
+		return result;
+
+	copy_from_user((void *) cmd, cmd_in, cmdlen);
+
+	/*
+	 * Obtain the data to be sent to the device (if any).
+	 */
+	copy_from_user((void *) buf,
+		       (void *) (cmd_in + cmdlen),
+		       inlen);
+
+	/*
+	 * Set the lun field to the correct value.
+	 */
+	cmd[1] = (cmd[1] & 0x1f) | (dev->lun << 5);
+
+	switch (opcode) {
+	case FORMAT_UNIT:
+		timeout = FORMAT_UNIT_TIMEOUT;
+		retries = 1;
+		break;
+	case START_STOP:
+		timeout = START_STOP_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case MOVE_MEDIUM:
+		timeout = MOVE_MEDIUM_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case READ_ELEMENT_STATUS:
+		timeout = READ_ELEMENT_STATUS_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	default:
+		timeout = NORMAL_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	}
 
 #ifndef DEBUG_NO_CMD
 
-    spin_lock_irqsave(&io_request_lock, flags);
-    
-    SCpnt = scsi_allocate_device(NULL, dev, 1);
-
-    {
-	DECLARE_MUTEX_LOCKED(sem);
-	SCpnt->request.sem = &sem;
-	scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
-		    timeout, retries);
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	SCpnt = scsi_allocate_device(NULL, dev, 1);
+
+	{
+		DECLARE_MUTEX_LOCKED(sem);
+		SCpnt->request.sem = &sem;
+		scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
+			    timeout, retries);
+		spin_unlock_irqrestore(&io_request_lock, flags);
+		down(&sem);
+		SCpnt->request.sem = NULL;
+	}
+
+	/* 
+	 * If there was an error condition, pass the info back to the user. 
+	 */
+	if (SCpnt->result) {
+		result = verify_area(VERIFY_WRITE,
+				     cmd_in,
+				     sizeof(SCpnt->sense_buffer));
+		if (result)
+			return result;
+		copy_to_user((void *) cmd_in,
+			     SCpnt->sense_buffer,
+			     sizeof(SCpnt->sense_buffer));
+	} else {
+		result = verify_area(VERIFY_WRITE, cmd_in, outlen);
+		if (result)
+			return result;
+		copy_to_user((void *) cmd_in, buf, outlen);
+	}
+	result = SCpnt->result;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+
+	wake_up(&SCpnt->device->device_wait);
+	SDpnt = SCpnt->device;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	if (buf)
+		scsi_free(buf, buf_needed);
+
+	if (SDpnt->scsi_request_fn)
+		(*SDpnt->scsi_request_fn) ();
+
 	spin_unlock_irqrestore(&io_request_lock, flags);
-	down(&sem);
-        SCpnt->request.sem = NULL;
-    }
-    
-    /* 
-     * If there was an error condition, pass the info back to the user. 
-     */
-    if(SCpnt->result) {
-        result = verify_area(VERIFY_WRITE, 
-                             cmd_in, 
-                             sizeof(SCpnt->sense_buffer));
-        if (result) return result;
-        copy_to_user((void *) cmd_in,  
-                    SCpnt->sense_buffer, 
-                    sizeof(SCpnt->sense_buffer));
-    } else {
-        result = verify_area(VERIFY_WRITE, cmd_in, outlen);
-        if (result) return result;
-        copy_to_user ((void *) cmd_in,  buf,  outlen);
-    }
-    result = SCpnt->result;
-
-    spin_lock_irqsave(&io_request_lock, flags);
-
-    wake_up(&SCpnt->device->device_wait);
-    SDpnt = SCpnt->device;
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if (buf) scsi_free(buf, buf_needed);
-    
-    if(SDpnt->scsi_request_fn)
-	(*SDpnt->scsi_request_fn)();
-    
-    spin_unlock_irqrestore(&io_request_lock, flags);
-    return result;
+	return result;
 #else
-    {
-	int i;
-	printk("scsi_ioctl : device %d.  command = ", dev->id);
-	for (i = 0; i < 12; ++i)
-	    printk("%02x ", cmd[i]);
-	printk("\nbuffer =");
-	for (i = 0; i < 20; ++i)
-	    printk("%02x ", buf[i]);
-	printk("\n");
-	printk("inlen = %d, outlen = %d, cmdlen = %d\n",
-	       inlen, outlen, cmdlen);
-	printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
-    }
-    return 0;
+	{
+		int i;
+		printk("scsi_ioctl : device %d.  command = ", dev->id);
+		for (i = 0; i < 12; ++i)
+			printk("%02x ", cmd[i]);
+		printk("\nbuffer =");
+		for (i = 0; i < 20; ++i)
+			printk("%02x ", buf[i]);
+		printk("\n");
+		printk("inlen = %d, outlen = %d, cmdlen = %d\n",
+		       inlen, outlen, cmdlen);
+		printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
+	}
+	return 0;
 #endif
 }
 
@@ -353,107 +365,115 @@
  * not take a major/minor number as the dev field.  Rather, it takes
  * a pointer to a scsi_devices[] element, a structure. 
  */
-int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
+int scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
 {
-    int result;
-    char scsi_cmd[12];
-    
-    /* No idea how this happens.... */
-    if (!dev) return -ENXIO;
-    
-    /*
-     * If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.
-     */
-    if( !scsi_block_when_processing_errors(dev) )
-      {
-        return -ENODEV;
-      }
-    
-    switch (cmd) {
-    case SCSI_IOCTL_GET_IDLUN:
-        result = verify_area(VERIFY_WRITE, arg, sizeof (Scsi_Idlun));
-        if (result) return result;
-
-	put_user(dev->id 
-                 + (dev->lun << 8) 
-                 + (dev->channel << 16)
-                 + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24),
-		    &((Scsi_Idlun *) arg)->dev_id);
-        put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
-	return 0;
-    case SCSI_IOCTL_GET_BUS_NUMBER:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user( dev->host->host_no, (int *) arg);
-	return 0;
-    case SCSI_IOCTL_TAGGED_ENABLE:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	if(!dev->tagged_supported) return -EINVAL;
-	dev->tagged_queue = 1;
-	dev->current_tag = 1;
-	return 0;
-    case SCSI_IOCTL_TAGGED_DISABLE:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	if(!dev->tagged_supported) return -EINVAL;
-	dev->tagged_queue = 0;
-	dev->current_tag = 0;
-	return 0;
-    case SCSI_IOCTL_PROBE_HOST:
-	return ioctl_probe(dev->host, arg);
-    case SCSI_IOCTL_SEND_COMMAND:
-	if(!capable(CAP_SYS_ADMIN))  return -EACCES;
-	return scsi_ioctl_send_command((Scsi_Device *) dev,
-				       (Scsi_Ioctl_Command *) arg);
-    case SCSI_IOCTL_DOORLOCK:
-	if (!dev->removable || !dev->lockable) return 0;
-	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
-	break;
-    case SCSI_IOCTL_DOORUNLOCK:
-	if (!dev->removable || !dev->lockable) return 0;
-	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
-    case SCSI_IOCTL_TEST_UNIT_READY:
-	scsi_cmd[0] = TEST_UNIT_READY;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = 0;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      NORMAL_TIMEOUT, NORMAL_RETRIES);
-	break;
-    case SCSI_IOCTL_START_UNIT:
-	scsi_cmd[0] = START_STOP;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = 1;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      START_STOP_TIMEOUT, NORMAL_RETRIES);
-	break;
-    case SCSI_IOCTL_STOP_UNIT:
-	scsi_cmd[0] = START_STOP;
-	scsi_cmd[1] = dev->lun << 5;
-	scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
-	scsi_cmd[4] = 0;
-	return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
-				      START_STOP_TIMEOUT, NORMAL_RETRIES);
-	break;
-    default :           
-	if (dev->host->hostt->ioctl)
-		return dev->host->hostt->ioctl(dev, cmd, arg);
+	int result;
+	char scsi_cmd[12];
+
+	/* No idea how this happens.... */
+	if (!dev)
+		return -ENXIO;
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(dev)) {
+		return -ENODEV;
+	}
+	switch (cmd) {
+	case SCSI_IOCTL_GET_IDLUN:
+		result = verify_area(VERIFY_WRITE, arg, sizeof(Scsi_Idlun));
+		if (result)
+			return result;
+
+		put_user(dev->id
+			 + (dev->lun << 8)
+			 + (dev->channel << 16)
+		  + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24),
+			 &((Scsi_Idlun *) arg)->dev_id);
+		put_user(dev->host->unique_id, &((Scsi_Idlun *) arg)->host_unique_id);
+		return 0;
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+		result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+		if (result)
+			return result;
+		put_user(dev->host->host_no, (int *) arg);
+		return 0;
+	case SCSI_IOCTL_TAGGED_ENABLE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (!dev->tagged_supported)
+			return -EINVAL;
+		dev->tagged_queue = 1;
+		dev->current_tag = 1;
+		return 0;
+	case SCSI_IOCTL_TAGGED_DISABLE:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		if (!dev->tagged_supported)
+			return -EINVAL;
+		dev->tagged_queue = 0;
+		dev->current_tag = 0;
+		return 0;
+	case SCSI_IOCTL_PROBE_HOST:
+		return ioctl_probe(dev->host, arg);
+	case SCSI_IOCTL_SEND_COMMAND:
+		if (!capable(CAP_SYS_ADMIN))
+			return -EACCES;
+		return scsi_ioctl_send_command((Scsi_Device *) dev,
+					     (Scsi_Ioctl_Command *) arg);
+	case SCSI_IOCTL_DOORLOCK:
+		if (!dev->removable || !dev->lockable)
+			return 0;
+		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+					 NORMAL_TIMEOUT, NORMAL_RETRIES);
+		break;
+	case SCSI_IOCTL_DOORUNLOCK:
+		if (!dev->removable || !dev->lockable)
+			return 0;
+		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+					 NORMAL_TIMEOUT, NORMAL_RETRIES);
+	case SCSI_IOCTL_TEST_UNIT_READY:
+		scsi_cmd[0] = TEST_UNIT_READY;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 0;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+					 NORMAL_TIMEOUT, NORMAL_RETRIES);
+		break;
+	case SCSI_IOCTL_START_UNIT:
+		scsi_cmd[0] = START_STOP;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 1;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+				     START_STOP_TIMEOUT, NORMAL_RETRIES);
+		break;
+	case SCSI_IOCTL_STOP_UNIT:
+		scsi_cmd[0] = START_STOP;
+		scsi_cmd[1] = dev->lun << 5;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 0;
+		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+				     START_STOP_TIMEOUT, NORMAL_RETRIES);
+		break;
+	default:
+		if (dev->host->hostt->ioctl)
+			return dev->host->hostt->ioctl(dev, cmd, arg);
+		return -EINVAL;
+	}
 	return -EINVAL;
-    }
-    return -EINVAL;
 }
 
 /*
@@ -461,14 +481,15 @@
  * fs segment fiddling.
  */
 
-int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
-    mm_segment_t oldfs;
-    int tmp;
-    oldfs = get_fs();
-    set_fs(get_ds());
-    tmp = scsi_ioctl (dev, cmd, arg);
-    set_fs(oldfs);
-    return tmp;
+int kernel_scsi_ioctl(Scsi_Device * dev, int cmd, void *arg)
+{
+	mm_segment_t oldfs;
+	int tmp;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	tmp = scsi_ioctl(dev, cmd, arg);
+	set_fs(oldfs);
+	return tmp;
 }
 
 /*
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_module.c linux/drivers/scsi/scsi_module.c
--- v2.3.16/linux/drivers/scsi/scsi_module.c	Sat Sep 20 11:42:33 1997
+++ linux/drivers/scsi/scsi_module.c	Sat Sep  4 10:48:46 1999
@@ -31,18 +31,20 @@
 
 #include <linux/module.h>
 
-int init_module(void) {
-    driver_template.module = &__this_module;
-    scsi_register_module(MODULE_SCSI_HA, &driver_template);
-    if (driver_template.present)
-	return 0;
+int init_module(void)
+{
+	driver_template.module = &__this_module;
+	scsi_register_module(MODULE_SCSI_HA, &driver_template);
+	if (driver_template.present)
+		return 0;
 
-    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
-    return -1;
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+	return -1;
 }
 
-void cleanup_module( void) {
-    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+void cleanup_module(void)
+{
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
 }
 
 /*
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c
--- v2.3.16/linux/drivers/scsi/scsi_obsolete.c	Sun Jan 17 18:29:54 1999
+++ linux/drivers/scsi/scsi_obsolete.c	Sat Sep  4 10:48:46 1999
@@ -33,7 +33,7 @@
  *#########################################################################
  *#########################################################################
  *#########################################################################
- *		NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE
+ *              NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE
  *
  *#########################################################################
  *#########################################################################
@@ -71,26 +71,26 @@
 #undef USE_STATIC_SCSI_MEMORY
 
 /*
-static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $";
-*/
+   static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $";
+ */
 
 
 #define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
 
 
-static int scsi_abort (Scsi_Cmnd *, int code);
-static int scsi_reset (Scsi_Cmnd *, unsigned int);
+static int scsi_abort(Scsi_Cmnd *, int code);
+static int scsi_reset(Scsi_Cmnd *, unsigned int);
 
-extern void scsi_old_done (Scsi_Cmnd *SCpnt);
-int update_timeout (Scsi_Cmnd *, int);
-extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
-extern void internal_cmnd (Scsi_Cmnd * SCpnt);
+extern void scsi_old_done(Scsi_Cmnd * SCpnt);
+int update_timeout(Scsi_Cmnd *, int);
+extern void scsi_old_times_out(Scsi_Cmnd * SCpnt);
+extern void internal_cmnd(Scsi_Cmnd * SCpnt);
 
-extern volatile struct Scsi_Host * host_active;
+extern volatile struct Scsi_Host *host_active;
 #define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
 			  || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
 
-static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+static unsigned char generic_sense[6] = {REQUEST_SENSE, 0, 0, 0, 255, 0};
 
 /*
  *  This is the number  of clock ticks we should wait before we time out
@@ -108,19 +108,19 @@
 
 
 #ifdef DEBUG
-    #define SCSI_TIMEOUT (5*HZ)
+#define SCSI_TIMEOUT (5*HZ)
 #else
-    #define SCSI_TIMEOUT (2*HZ)
+#define SCSI_TIMEOUT (2*HZ)
 #endif
 
 #ifdef DEBUG
-    #define SENSE_TIMEOUT SCSI_TIMEOUT
-    #define ABORT_TIMEOUT SCSI_TIMEOUT
-    #define RESET_TIMEOUT SCSI_TIMEOUT
+#define SENSE_TIMEOUT SCSI_TIMEOUT
+#define ABORT_TIMEOUT SCSI_TIMEOUT
+#define RESET_TIMEOUT SCSI_TIMEOUT
 #else
-    #define SENSE_TIMEOUT (5*HZ/10)
-    #define RESET_TIMEOUT (5*HZ/10)
-    #define ABORT_TIMEOUT (5*HZ/10)
+#define SENSE_TIMEOUT (5*HZ/10)
+#define RESET_TIMEOUT (5*HZ/10)
+#define ABORT_TIMEOUT (5*HZ/10)
 #endif
 
 
@@ -144,67 +144,66 @@
  * command, that failing perform a kernel panic.
  */
 
-void scsi_old_times_out (Scsi_Cmnd * SCpnt)
+void scsi_old_times_out(Scsi_Cmnd * SCpnt)
 {
-    unsigned long flags;
+	unsigned long flags;
 
-    spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&io_request_lock, flags);
 
-    /* Set the serial_number_at_timeout to the current serial_number */
-    SCpnt->serial_number_at_timeout = SCpnt->serial_number;
+	/* Set the serial_number_at_timeout to the current serial_number */
+	SCpnt->serial_number_at_timeout = SCpnt->serial_number;
 
-    switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
-    {
-    case NORMAL_TIMEOUT:
-	{
+	switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3)) {
+	case NORMAL_TIMEOUT:
+		{
 #ifdef DEBUG_TIMEOUT
-	    scsi_dump_status();
+			scsi_dump_status();
 #endif
-	}
+		}
 
-	if (!scsi_abort (SCpnt, DID_TIME_OUT))
-	    break;
-    case IN_ABORT:
-	printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
-	       SCpnt->host->host_no, SCpnt->pid);
-	if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
-	    break;
-    case IN_RESET:
-    case (IN_ABORT | IN_RESET):
-	/* This might be controversial, but if there is a bus hang,
-	 * you might conceivably want the machine up and running
-	 * esp if you have an ide disk.
-	 */
-	printk("SCSI host %d channel %d reset (pid %ld) timed out - "
-               "trying harder\n",
-	       SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
-	SCpnt->internal_timeout &= ~IN_RESET;
-	SCpnt->internal_timeout |= IN_RESET2;
-        scsi_reset (SCpnt,
-		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
-        break;
-    case IN_RESET2:
-    case (IN_ABORT | IN_RESET2):
-	/* Obviously the bus reset didn't work.
-	 * Let's try even harder and call for an HBA reset.
-         * Maybe the HBA itself crashed and this will shake it loose.
-	 */
-	printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
-	       SCpnt->host->host_no, SCpnt->pid);
-	SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
-	SCpnt->internal_timeout |= IN_RESET3;
-        scsi_reset (SCpnt,
-		    SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
-	break;
-
-    default:
-	printk("SCSI host %d reset (pid %ld) timed out again -\n",
-	       SCpnt->host->host_no, SCpnt->pid);
-	printk("probably an unrecoverable SCSI bus or device hang.\n");
-	break;
+		if (!scsi_abort(SCpnt, DID_TIME_OUT))
+			break;
+	case IN_ABORT:
+		printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
+		       SCpnt->host->host_no, SCpnt->pid);
+		if (!scsi_reset(SCpnt, SCSI_RESET_ASYNCHRONOUS))
+			break;
+	case IN_RESET:
+	case (IN_ABORT | IN_RESET):
+		/* This might be controversial, but if there is a bus hang,
+		 * you might conceivably want the machine up and running
+		 * esp if you have an ide disk.
+		 */
+		printk("SCSI host %d channel %d reset (pid %ld) timed out - "
+		       "trying harder\n",
+		       SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
+		SCpnt->internal_timeout &= ~IN_RESET;
+		SCpnt->internal_timeout |= IN_RESET2;
+		scsi_reset(SCpnt,
+		 SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
+		break;
+	case IN_RESET2:
+	case (IN_ABORT | IN_RESET2):
+		/* Obviously the bus reset didn't work.
+		 * Let's try even harder and call for an HBA reset.
+		 * Maybe the HBA itself crashed and this will shake it loose.
+		 */
+		printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
+		       SCpnt->host->host_no, SCpnt->pid);
+		SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
+		SCpnt->internal_timeout |= IN_RESET3;
+		scsi_reset(SCpnt,
+		SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
+		break;
 
-    }
-    spin_unlock_irqrestore(&io_request_lock, flags);
+	default:
+		printk("SCSI host %d reset (pid %ld) timed out again -\n",
+		       SCpnt->host->host_no, SCpnt->pid);
+		printk("probably an unrecoverable SCSI bus or device hang.\n");
+		break;
+
+	}
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
 }
 
@@ -214,92 +213,89 @@
  *  io_request_lock already held, so we need do nothing here about grabbing
  *  any locks.
  */
-static void scsi_request_sense (Scsi_Cmnd * SCpnt)
+static void scsi_request_sense(Scsi_Cmnd * SCpnt)
 {
-    SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
-    update_timeout(SCpnt, SENSE_TIMEOUT);
+	SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
+	update_timeout(SCpnt, SENSE_TIMEOUT);
 
 
-    memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
-	    sizeof(generic_sense));
-    memset ((void *) SCpnt->sense_buffer, 0,
-            sizeof(SCpnt->sense_buffer));
-
-    SCpnt->cmnd[1] = SCpnt->lun << 5;
-    SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-
-    SCpnt->request_buffer = &SCpnt->sense_buffer;
-    SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
-    SCpnt->use_sg = 0;
-    SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-    SCpnt->result = 0;
-    internal_cmnd (SCpnt);
+	memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
+	       sizeof(generic_sense));
+	memset((void *) SCpnt->sense_buffer, 0,
+	       sizeof(SCpnt->sense_buffer));
+
+	SCpnt->cmnd[1] = SCpnt->lun << 5;
+	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+	SCpnt->request_buffer = &SCpnt->sense_buffer;
+	SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+	SCpnt->use_sg = 0;
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->result = 0;
+	internal_cmnd(SCpnt);
 }
 
 
 
 
-static int check_sense (Scsi_Cmnd * SCpnt)
+static int check_sense(Scsi_Cmnd * SCpnt)
 {
-    /* If there is no sense information, request it.  If we have already
-     * requested it, there is no point in asking again - the firmware must
-     * be confused.
-     */
-    if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
-	if(!(SCpnt->flags & ASKED_FOR_SENSE))
-	    return SUGGEST_SENSE;
-	else
-	    return SUGGEST_RETRY;
-    }
-
-    SCpnt->flags &= ~ASKED_FOR_SENSE;
+	/* If there is no sense information, request it.  If we have already
+	 * requested it, there is no point in asking again - the firmware must
+	 * be confused.
+	 */
+	if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+		if (!(SCpnt->flags & ASKED_FOR_SENSE))
+			return SUGGEST_SENSE;
+		else
+			return SUGGEST_RETRY;
+	}
+	SCpnt->flags &= ~ASKED_FOR_SENSE;
 
 #ifdef DEBUG_INIT
-    printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
-    print_sense("", SCpnt);
-    printk("\n");
-#endif
-    if (SCpnt->sense_buffer[2] & 0xe0)
-	return SUGGEST_ABORT;
-
-    switch (SCpnt->sense_buffer[2] & 0xf)
-    {
-    case NO_SENSE:
-	return 0;
-    case RECOVERED_ERROR:
-	return SUGGEST_IS_OK;
-
-    case ABORTED_COMMAND:
-	return SUGGEST_RETRY;
-    case NOT_READY:
-    case UNIT_ATTENTION:
-        /*
-         * If we are expecting a CC/UA because of a bus reset that we
-         * performed, treat this just as a retry.  Otherwise this is
-         * information that we should pass up to the upper-level driver
-         * so that we can deal with it there.
-         */
-        if( SCpnt->device->expecting_cc_ua )
-        {
-            SCpnt->device->expecting_cc_ua = 0;
-            return SUGGEST_RETRY;
-        }
-	return SUGGEST_ABORT;
-
-    /* these three are not supported */
-    case COPY_ABORTED:
-    case VOLUME_OVERFLOW:
-    case MISCOMPARE:
-
-    case MEDIUM_ERROR:
-	return SUGGEST_REMAP;
-    case BLANK_CHECK:
-    case DATA_PROTECT:
-    case HARDWARE_ERROR:
-    case ILLEGAL_REQUEST:
-    default:
-	return SUGGEST_ABORT;
-    }
+	printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
+	print_sense("", SCpnt);
+	printk("\n");
+#endif
+	if (SCpnt->sense_buffer[2] & 0xe0)
+		return SUGGEST_ABORT;
+
+	switch (SCpnt->sense_buffer[2] & 0xf) {
+	case NO_SENSE:
+		return 0;
+	case RECOVERED_ERROR:
+		return SUGGEST_IS_OK;
+
+	case ABORTED_COMMAND:
+		return SUGGEST_RETRY;
+	case NOT_READY:
+	case UNIT_ATTENTION:
+		/*
+		 * If we are expecting a CC/UA because of a bus reset that we
+		 * performed, treat this just as a retry.  Otherwise this is
+		 * information that we should pass up to the upper-level driver
+		 * so that we can deal with it there.
+		 */
+		if (SCpnt->device->expecting_cc_ua) {
+			SCpnt->device->expecting_cc_ua = 0;
+			return SUGGEST_RETRY;
+		}
+		return SUGGEST_ABORT;
+
+		/* these three are not supported */
+	case COPY_ABORTED:
+	case VOLUME_OVERFLOW:
+	case MISCOMPARE:
+
+	case MEDIUM_ERROR:
+		return SUGGEST_REMAP;
+	case BLANK_CHECK:
+	case DATA_PROTECT:
+	case HARDWARE_ERROR:
+	case ILLEGAL_REQUEST:
+	default:
+		return SUGGEST_ABORT;
+	}
 }
 
 /* This function is the mid-level interrupt routine, which decides how
@@ -323,29 +319,30 @@
  *      will hang. If more than one of the above actions are taken by
  *      scsi_done, then unpredictable behavior will result.
  */
-void scsi_old_done (Scsi_Cmnd * SCpnt)
+void scsi_old_done(Scsi_Cmnd * SCpnt)
 {
-    int status=0;
-    int exit=0;
-    int checked;
-    int oldto;
-    struct Scsi_Host * host = SCpnt->host;
-    int result = SCpnt->result;
-    SCpnt->serial_number = 0;
-    SCpnt->serial_number_at_timeout = 0;
-    oldto = update_timeout(SCpnt, 0);
+	int status = 0;
+	int exit = 0;
+	int checked;
+	int oldto;
+	struct Scsi_Host *host = SCpnt->host;
+	int result = SCpnt->result;
+	SCpnt->serial_number = 0;
+	SCpnt->serial_number_at_timeout = 0;
+	oldto = update_timeout(SCpnt, 0);
 
 #ifdef DEBUG_TIMEOUT
-    if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
-		      result, SCpnt->target, SCpnt->lun);
+	if (result)
+		printk("Non-zero result in scsi_done %x %d:%d\n",
+		       result, SCpnt->target, SCpnt->lun);
 #endif
 
-    /* If we requested an abort, (and we got it) then fix up the return
-     *  status to say why
-     */
-    if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
-	SCpnt->result = result = (result & 0xff00ffff) |
-	    (SCpnt->abort_reason << 16);
+	/* If we requested an abort, (and we got it) then fix up the return
+	 *  status to say why
+	 */
+	if (host_byte(result) == DID_ABORT && SCpnt->abort_reason)
+		SCpnt->result = result = (result & 0xff00ffff) |
+		    (SCpnt->abort_reason << 16);
 
 
 #define CMD_FINISHED 0
@@ -354,339 +351,313 @@
 #define PENDING  4
 
 #ifdef DEBUG
-    printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
+	printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
 #endif
 
-    if(SCpnt->flags & SYNC_RESET)
-    {
-        /*
-        * The behaviou of scsi_reset(SYNC) was changed in 2.1.? .
-        * The scsi mid-layer does a REDO after every sync reset, the driver
-        * must not do that any more. In order to prevent old drivers from
-        * crashing, all scsi_done() calls during sync resets are ignored.
-        */
-        printk("scsi%d: device driver called scsi_done() "
-	       "for a syncronous reset.\n", SCpnt->host->host_no);
-        return;
-    }
-    if(SCpnt->flags & WAS_SENSE)
-    {
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-    }
-
-    switch (host_byte(result))
-    {
-    case DID_OK:
-	if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
-	    /* Failed to obtain sense information */
-	{
-	    SCpnt->flags &= ~WAS_SENSE;
-#if 0	/* This cannot possibly be correct. */
-	    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-#endif
-
-	    if (!(SCpnt->flags & WAS_RESET))
-	    {
-		printk("scsi%d : channel %d target %d lun %d request sense"
-		       " failed, performing reset.\n",
-		       SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
-		       SCpnt->lun);
-		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
-		status = REDO;
-                break;
-	    }
-	    else
-	    {
-		exit = (DRIVER_HARD | SUGGEST_ABORT);
-		status = CMD_FINISHED;
-	    }
+	if (SCpnt->flags & SYNC_RESET) {
+		/*
+		   * The behaviou of scsi_reset(SYNC) was changed in 2.1.? .
+		   * The scsi mid-layer does a REDO after every sync reset, the driver
+		   * must not do that any more. In order to prevent old drivers from
+		   * crashing, all scsi_done() calls during sync resets are ignored.
+		 */
+		printk("scsi%d: device driver called scsi_done() "
+		       "for a syncronous reset.\n", SCpnt->host->host_no);
+		return;
 	}
-	else switch(msg_byte(result))
-	{
-	case COMMAND_COMPLETE:
-	    switch (status_byte(result))
-	    {
-	    case GOOD:
-		if (SCpnt->flags & WAS_SENSE)
+	if (SCpnt->flags & WAS_SENSE) {
+		SCpnt->use_sg = SCpnt->old_use_sg;
+		SCpnt->cmd_len = SCpnt->old_cmd_len;
+	}
+	switch (host_byte(result)) {
+	case DID_OK:
+		if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
+			/* Failed to obtain sense information */
 		{
+			SCpnt->flags &= ~WAS_SENSE;
+#if 0				/* This cannot possibly be correct. */
+			SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
+
+			if (!(SCpnt->flags & WAS_RESET)) {
+				printk("scsi%d : channel %d target %d lun %d request sense"
+				       " failed, performing reset.\n",
+				       SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
+				       SCpnt->lun);
+				scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+				status = REDO;
+				break;
+			} else {
+				exit = (DRIVER_HARD | SUGGEST_ABORT);
+				status = CMD_FINISHED;
+			}
+		} else
+			switch (msg_byte(result)) {
+			case COMMAND_COMPLETE:
+				switch (status_byte(result)) {
+				case GOOD:
+					if (SCpnt->flags & WAS_SENSE) {
 #ifdef DEBUG
-		    printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
-                            "parsing sense information.\n");
+						printk("In scsi_done, GOOD status, COMMAND COMPLETE, "
+						       "parsing sense information.\n");
 #endif
-		    SCpnt->flags &= ~WAS_SENSE;
-#if 0	/* This cannot possibly be correct. */
-		    SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+						SCpnt->flags &= ~WAS_SENSE;
+#if 0				/* This cannot possibly be correct. */
+						SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
 #endif
 
-		    switch (checked = check_sense(SCpnt))
-		    {
-		    case SUGGEST_SENSE:
-		    case 0:
+						switch (checked = check_sense(SCpnt)) {
+						case SUGGEST_SENSE:
+						case 0:
 #ifdef DEBUG
-			printk("NO SENSE.  status = REDO\n");
+							printk("NO SENSE.  status = REDO\n");
 #endif
-			update_timeout(SCpnt, oldto);
-			status = REDO;
-			break;
-		    case SUGGEST_IS_OK:
-			break;
-		    case SUGGEST_REMAP:
+							update_timeout(SCpnt, oldto);
+							status = REDO;
+							break;
+						case SUGGEST_IS_OK:
+							break;
+						case SUGGEST_REMAP:
 #ifdef DEBUG
-			printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n");
+							printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n");
 #endif
-			status = CMD_FINISHED;
-			exit = DRIVER_SENSE | SUGGEST_ABORT;
-			break;
-		    case SUGGEST_RETRY:
+							status = CMD_FINISHED;
+							exit = DRIVER_SENSE | SUGGEST_ABORT;
+							break;
+						case SUGGEST_RETRY:
 #ifdef DEBUG
-			printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
+							printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
 #endif
-			status = MAYREDO;
-			exit = DRIVER_SENSE | SUGGEST_RETRY;
-			break;
-		    case SUGGEST_ABORT:
+							status = MAYREDO;
+							exit = DRIVER_SENSE | SUGGEST_RETRY;
+							break;
+						case SUGGEST_ABORT:
 #ifdef DEBUG
-			printk("SENSE SUGGEST ABORT - status = CMD_FINISHED");
+							printk("SENSE SUGGEST ABORT - status = CMD_FINISHED");
 #endif
-			status = CMD_FINISHED;
-			exit =  DRIVER_SENSE | SUGGEST_ABORT;
-			break;
-		    default:
-			printk ("Internal error %s %d \n", __FILE__,
-				__LINE__);
-		    }
-		} /* end WAS_SENSE */
-		else
-		{
+							status = CMD_FINISHED;
+							exit = DRIVER_SENSE | SUGGEST_ABORT;
+							break;
+						default:
+							printk("Internal error %s %d \n", __FILE__,
+							       __LINE__);
+						}
+					}
+					/* end WAS_SENSE */ 
+					else {
 #ifdef DEBUG
-		    printk("COMMAND COMPLETE message returned, "
-                           "status = CMD_FINISHED. \n");
+						printk("COMMAND COMPLETE message returned, "
+						       "status = CMD_FINISHED. \n");
 #endif
-		    exit =  DRIVER_OK;
-		    status = CMD_FINISHED;
-		}
-		break;
-
-	    case CHECK_CONDITION:
-	    case COMMAND_TERMINATED:
-		switch (check_sense(SCpnt))
-		{
-		case 0:
-		    update_timeout(SCpnt, oldto);
-		    status = REDO;
-		    break;
-		case SUGGEST_REMAP:
-		    status = CMD_FINISHED;
-		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
-		    break;
-		case SUGGEST_RETRY:
-		    status = MAYREDO;
-		    exit = DRIVER_SENSE | SUGGEST_RETRY;
-		    break;
-		case SUGGEST_ABORT:
-		    status = CMD_FINISHED;
-		    exit =  DRIVER_SENSE | SUGGEST_ABORT;
-		    break;
-		case SUGGEST_SENSE:
-		    scsi_request_sense (SCpnt);
-		    status = PENDING;
-		    break;
-		}
-		break;
-
-	    case CONDITION_GOOD:
-	    case INTERMEDIATE_GOOD:
-	    case INTERMEDIATE_C_GOOD:
+						exit = DRIVER_OK;
+						status = CMD_FINISHED;
+					}
+					break;
+
+				case CHECK_CONDITION:
+				case COMMAND_TERMINATED:
+					switch (check_sense(SCpnt)) {
+					case 0:
+						update_timeout(SCpnt, oldto);
+						status = REDO;
+						break;
+					case SUGGEST_REMAP:
+						status = CMD_FINISHED;
+						exit = DRIVER_SENSE | SUGGEST_ABORT;
+						break;
+					case SUGGEST_RETRY:
+						status = MAYREDO;
+						exit = DRIVER_SENSE | SUGGEST_RETRY;
+						break;
+					case SUGGEST_ABORT:
+						status = CMD_FINISHED;
+						exit = DRIVER_SENSE | SUGGEST_ABORT;
+						break;
+					case SUGGEST_SENSE:
+						scsi_request_sense(SCpnt);
+						status = PENDING;
+						break;
+					}
+					break;
+
+				case CONDITION_GOOD:
+				case INTERMEDIATE_GOOD:
+				case INTERMEDIATE_C_GOOD:
+					break;
+
+				case BUSY:
+				case QUEUE_FULL:
+					update_timeout(SCpnt, oldto);
+					status = REDO;
+					break;
+
+				case RESERVATION_CONFLICT:
+					printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
+					       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
+					scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+					status = REDO;
+					break;
+				default:
+					printk("Internal error %s %d \n"
+					 "status byte = %d \n", __FILE__,
+					  __LINE__, status_byte(result));
+
+				}
+				break;
+			default:
+				panic("scsi: unsupported message byte %d received\n",
+				      msg_byte(result));
+			}
 		break;
-
-	    case BUSY:
-	    case QUEUE_FULL:
-		update_timeout(SCpnt, oldto);
-		status = REDO;
-		break;
-
-	    case RESERVATION_CONFLICT:
-		printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
-		       " reset.\n", SCpnt->host->host_no, SCpnt->channel);
-                scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
-		status = REDO;
-		break;
-	    default:
-		printk ("Internal error %s %d \n"
-			"status byte = %d \n", __FILE__,
-			__LINE__, status_byte(result));
-
-	    }
-	    break;
-	default:
-	    panic("scsi: unsupported message byte %d received\n",
-		  msg_byte(result));
-	}
-	break;
-    case DID_TIME_OUT:
+	case DID_TIME_OUT:
 #ifdef DEBUG
-	printk("Host returned DID_TIME_OUT - ");
+		printk("Host returned DID_TIME_OUT - ");
 #endif
 
-	if (SCpnt->flags & WAS_TIMEDOUT)
-	{
+		if (SCpnt->flags & WAS_TIMEDOUT) {
 #ifdef DEBUG
-	    printk("Aborting\n");
+			printk("Aborting\n");
 #endif
-	    /*
-	      Allow TEST_UNIT_READY and INQUIRY commands to timeout early
-	      without causing resets.  All other commands should be retried.
-	    */
-	    if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
-		SCpnt->cmnd[0] != INQUIRY)
-		    status = MAYREDO;
-	    exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
-	}
-	else
-	{
+			/*
+			   Allow TEST_UNIT_READY and INQUIRY commands to timeout early
+			   without causing resets.  All other commands should be retried.
+			 */
+			if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
+			    SCpnt->cmnd[0] != INQUIRY)
+				status = MAYREDO;
+			exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+		} else {
 #ifdef DEBUG
-	    printk ("Retrying.\n");
+			printk("Retrying.\n");
 #endif
-	    SCpnt->flags  |= WAS_TIMEDOUT;
-	    SCpnt->internal_timeout &= ~IN_ABORT;
-	    status = REDO;
-	}
-	break;
-    case DID_BUS_BUSY:
-    case DID_PARITY:
-	status = REDO;
-	break;
-    case DID_NO_CONNECT:
+			SCpnt->flags |= WAS_TIMEDOUT;
+			SCpnt->internal_timeout &= ~IN_ABORT;
+			status = REDO;
+		}
+		break;
+	case DID_BUS_BUSY:
+	case DID_PARITY:
+		status = REDO;
+		break;
+	case DID_NO_CONNECT:
 #ifdef DEBUG
-	printk("Couldn't connect.\n");
+		printk("Couldn't connect.\n");
 #endif
-	exit  = (DRIVER_HARD | SUGGEST_ABORT);
-	break;
-    case DID_ERROR:
-	status = MAYREDO;
-	exit = (DRIVER_HARD | SUGGEST_ABORT);
-	break;
-    case DID_BAD_TARGET:
-    case DID_ABORT:
-	exit = (DRIVER_INVALID | SUGGEST_ABORT);
-	break;
-    case DID_RESET:
-	if (SCpnt->flags & IS_RESETTING)
-	{
-	    SCpnt->flags &= ~IS_RESETTING;
-	    status = REDO;
-	    break;
-	}
-
-	if(msg_byte(result) == GOOD &&
-	   status_byte(result) == CHECK_CONDITION) {
-	    switch (check_sense(SCpnt)) {
-	    case 0:
-		update_timeout(SCpnt, oldto);
-		status = REDO;
+		exit = (DRIVER_HARD | SUGGEST_ABORT);
 		break;
-	    case SUGGEST_REMAP:
-	    case SUGGEST_RETRY:
+	case DID_ERROR:
 		status = MAYREDO;
-		exit = DRIVER_SENSE | SUGGEST_RETRY;
+		exit = (DRIVER_HARD | SUGGEST_ABORT);
 		break;
-	    case SUGGEST_ABORT:
-		status = CMD_FINISHED;
-		exit =  DRIVER_SENSE | SUGGEST_ABORT;
+	case DID_BAD_TARGET:
+	case DID_ABORT:
+		exit = (DRIVER_INVALID | SUGGEST_ABORT);
 		break;
-	    case SUGGEST_SENSE:
-		scsi_request_sense (SCpnt);
-		status = PENDING;
+	case DID_RESET:
+		if (SCpnt->flags & IS_RESETTING) {
+			SCpnt->flags &= ~IS_RESETTING;
+			status = REDO;
+			break;
+		}
+		if (msg_byte(result) == GOOD &&
+		    status_byte(result) == CHECK_CONDITION) {
+			switch (check_sense(SCpnt)) {
+			case 0:
+				update_timeout(SCpnt, oldto);
+				status = REDO;
+				break;
+			case SUGGEST_REMAP:
+			case SUGGEST_RETRY:
+				status = MAYREDO;
+				exit = DRIVER_SENSE | SUGGEST_RETRY;
+				break;
+			case SUGGEST_ABORT:
+				status = CMD_FINISHED;
+				exit = DRIVER_SENSE | SUGGEST_ABORT;
+				break;
+			case SUGGEST_SENSE:
+				scsi_request_sense(SCpnt);
+				status = PENDING;
+				break;
+			}
+		} else {
+			status = REDO;
+			exit = SUGGEST_RETRY;
+		}
 		break;
-	    }
-	} else {
-	    status=REDO;
-	    exit = SUGGEST_RETRY;
+	default:
+		exit = (DRIVER_ERROR | SUGGEST_DIE);
 	}
-	break;
-    default :
-	exit = (DRIVER_ERROR | SUGGEST_DIE);
-    }
-
-    switch (status)
-    {
-    case CMD_FINISHED:
-    case PENDING:
-	break;
-    case MAYREDO:
+
+	switch (status) {
+	case CMD_FINISHED:
+	case PENDING:
+		break;
+	case MAYREDO:
 #ifdef DEBUG
-	printk("In MAYREDO, allowing %d retries, have %d\n",
-	       SCpnt->allowed, SCpnt->retries);
+		printk("In MAYREDO, allowing %d retries, have %d\n",
+		       SCpnt->allowed, SCpnt->retries);
 #endif
-	if ((++SCpnt->retries) < SCpnt->allowed)
-	{
-	    if ((SCpnt->retries >= (SCpnt->allowed >> 1))
-		&& !(SCpnt->host->resetting && time_before(jiffies, SCpnt->host->last_reset + MIN_RESET_PERIOD))
-		&& !(SCpnt->flags & WAS_RESET))
-	    {
-		printk("scsi%d channel %d : resetting for second half of retries.\n",
-		       SCpnt->host->host_no, SCpnt->channel);
-		scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+		if ((++SCpnt->retries) < SCpnt->allowed) {
+			if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+			    && !(SCpnt->host->resetting && time_before(jiffies, SCpnt->host->last_reset + MIN_RESET_PERIOD))
+			    && !(SCpnt->flags & WAS_RESET)) {
+				printk("scsi%d channel %d : resetting for second half of retries.\n",
+				   SCpnt->host->host_no, SCpnt->channel);
+				scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+				/* fall through to REDO */
+			}
+		} else {
+			status = CMD_FINISHED;
+			break;
+		}
 		/* fall through to REDO */
-	    }
-	}
-	else
-	{
-	    status = CMD_FINISHED;
-	    break;
-	}
-	/* fall through to REDO */
 
-    case REDO:
+	case REDO:
 
-	if (SCpnt->flags & WAS_SENSE)
-	    scsi_request_sense(SCpnt);
-	else
-	{
-	    memcpy ((void *) SCpnt->cmnd,
-		    (void*) SCpnt->data_cmnd,
-		    sizeof(SCpnt->data_cmnd));
-            memset ((void *) SCpnt->sense_buffer, 0,
-                    sizeof(SCpnt->sense_buffer));
-	    SCpnt->request_buffer = SCpnt->buffer;
-	    SCpnt->request_bufflen = SCpnt->bufflen;
-	    SCpnt->use_sg = SCpnt->old_use_sg;
-	    SCpnt->cmd_len = SCpnt->old_cmd_len;
-            SCpnt->result = 0;
-	    internal_cmnd (SCpnt);
+		if (SCpnt->flags & WAS_SENSE)
+			scsi_request_sense(SCpnt);
+		else {
+			memcpy((void *) SCpnt->cmnd,
+			       (void *) SCpnt->data_cmnd,
+			       sizeof(SCpnt->data_cmnd));
+			memset((void *) SCpnt->sense_buffer, 0,
+			       sizeof(SCpnt->sense_buffer));
+			SCpnt->request_buffer = SCpnt->buffer;
+			SCpnt->request_bufflen = SCpnt->bufflen;
+			SCpnt->use_sg = SCpnt->old_use_sg;
+			SCpnt->cmd_len = SCpnt->old_cmd_len;
+			SCpnt->result = 0;
+			internal_cmnd(SCpnt);
+		}
+		break;
+	default:
+		INTERNAL_ERROR;
 	}
-	break;
-    default:
-	INTERNAL_ERROR;
-    }
 
-    if (status == CMD_FINISHED) {
+	if (status == CMD_FINISHED) {
 #ifdef DEBUG
-	printk("Calling done function - at address %p\n", SCpnt->done);
+		printk("Calling done function - at address %p\n", SCpnt->done);
 #endif
-	host->host_busy--; /* Indicate that we are free */
-
-	if (host->block && host->host_busy == 0) {
-	    host_active = NULL;
+		host->host_busy--;	/* Indicate that we are free */
 
-	    /* For block devices "wake_up" is done in end_scsi_request */
-	    if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) {
-		struct Scsi_Host * next;
+		if (host->block && host->host_busy == 0) {
+			host_active = NULL;
 
-		for (next = host->block; next != host; next = next->block)
-		    wake_up(&next->host_wait);
-	    }
+			/* For block devices "wake_up" is done in end_scsi_request */
+			if (!SCSI_BLK_MAJOR(MAJOR(SCpnt->request.rq_dev))) {
+				struct Scsi_Host *next;
 
+				for (next = host->block; next != host; next = next->block)
+					wake_up(&next->host_wait);
+			}
+		}
+		wake_up(&host->host_wait);
+		SCpnt->result = result | ((exit & 0xff) << 24);
+		SCpnt->use_sg = SCpnt->old_use_sg;
+		SCpnt->cmd_len = SCpnt->old_cmd_len;
+		SCpnt->done(SCpnt);
 	}
-
-	wake_up(&host->host_wait);
-	SCpnt->result = result | ((exit & 0xff) << 24);
-	SCpnt->use_sg = SCpnt->old_use_sg;
-	SCpnt->cmd_len = SCpnt->old_cmd_len;
-	SCpnt->done (SCpnt);
-    }
-
 #undef CMD_FINISHED
 #undef REDO
 #undef MAYREDO
@@ -709,110 +680,104 @@
  */
 
 
-static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
+static int scsi_abort(Scsi_Cmnd * SCpnt, int why)
 {
-    int oldto;
-    struct Scsi_Host * host = SCpnt->host;
-
-    while(1)
-    {
+	int oldto;
+	struct Scsi_Host *host = SCpnt->host;
 
-	/*
-	 * Protect against races here.  If the command is done, or we are
-	 * on a different command forget it.
-	 */
-	if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-	    return 0;
-	}
+	while (1) {
 
-	if (SCpnt->internal_timeout & IN_ABORT)
-	{
-	    spin_unlock_irq(&io_request_lock);
-	    while (SCpnt->internal_timeout & IN_ABORT)
-		barrier();
-	    spin_lock_irq(&io_request_lock);
-	}
-	else
-	{
-	    SCpnt->internal_timeout |= IN_ABORT;
-	    oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
-
-	    if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
-		/* OK, this command must have died when we did the
-		 *  reset.  The device itself must have lied.
-		 */
-		printk("Stale command on %d %d:%d appears to have died when"
-		       " the bus was reset\n",
-		       SCpnt->channel, SCpnt->target, SCpnt->lun);
-	    }
-
-	    if (!host->host_busy) {
-		SCpnt->internal_timeout &= ~IN_ABORT;
-		update_timeout(SCpnt, oldto);
-		return 0;
-	    }
-	    printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
-		   " channel %d, id %d, lun %d ",
-		   SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
-		   (int) SCpnt->target, (int) SCpnt->lun);
-	    print_command (SCpnt->cmnd);
-	    if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
-		return 0;
-	    SCpnt->abort_reason = why;
-	    switch(host->hostt->abort(SCpnt)) {
-		/* We do not know how to abort.  Try waiting another
-		 * time increment and see if this helps. Set the
-		 * WAS_TIMEDOUT flag set so we do not try this twice
+		/*
+		 * Protect against races here.  If the command is done, or we are
+		 * on a different command forget it.
 		 */
-	    case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
-				   * this is too severe
-				   */
-	    case SCSI_ABORT_SNOOZE:
-		if(why == DID_TIME_OUT) {
-		    SCpnt->internal_timeout &= ~IN_ABORT;
-		    if(SCpnt->flags & WAS_TIMEDOUT) {
-			return 1; /* Indicate we cannot handle this.
-				   * We drop down into the reset handler
-				   * and try again
-				   */
-		    } else {
-			SCpnt->flags |= WAS_TIMEDOUT;
-			oldto = SCpnt->timeout_per_command;
-			update_timeout(SCpnt, oldto);
-		    }
+		if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+			return 0;
 		}
-		return 0;
-	    case SCSI_ABORT_PENDING:
-		if(why != DID_TIME_OUT) {
-		    update_timeout(SCpnt, oldto);
+		if (SCpnt->internal_timeout & IN_ABORT) {
+			spin_unlock_irq(&io_request_lock);
+			while (SCpnt->internal_timeout & IN_ABORT)
+				barrier();
+			spin_lock_irq(&io_request_lock);
+		} else {
+			SCpnt->internal_timeout |= IN_ABORT;
+			oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
+
+			if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
+				/* OK, this command must have died when we did the
+				 *  reset.  The device itself must have lied.
+				 */
+				printk("Stale command on %d %d:%d appears to have died when"
+				       " the bus was reset\n",
+				       SCpnt->channel, SCpnt->target, SCpnt->lun);
+			}
+			if (!host->host_busy) {
+				SCpnt->internal_timeout &= ~IN_ABORT;
+				update_timeout(SCpnt, oldto);
+				return 0;
+			}
+			printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
+			       " channel %d, id %d, lun %d ",
+			       SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
+			       (int) SCpnt->target, (int) SCpnt->lun);
+			print_command(SCpnt->cmnd);
+			if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
+				return 0;
+			SCpnt->abort_reason = why;
+			switch (host->hostt->abort(SCpnt)) {
+				/* We do not know how to abort.  Try waiting another
+				 * time increment and see if this helps. Set the
+				 * WAS_TIMEDOUT flag set so we do not try this twice
+				 */
+			case SCSI_ABORT_BUSY:	/* Tough call - returning 1 from
+						 * this is too severe
+						 */
+			case SCSI_ABORT_SNOOZE:
+				if (why == DID_TIME_OUT) {
+					SCpnt->internal_timeout &= ~IN_ABORT;
+					if (SCpnt->flags & WAS_TIMEDOUT) {
+						return 1;	/* Indicate we cannot handle this.
+								 * We drop down into the reset handler
+								 * and try again
+								 */
+					} else {
+						SCpnt->flags |= WAS_TIMEDOUT;
+						oldto = SCpnt->timeout_per_command;
+						update_timeout(SCpnt, oldto);
+					}
+				}
+				return 0;
+			case SCSI_ABORT_PENDING:
+				if (why != DID_TIME_OUT) {
+					update_timeout(SCpnt, oldto);
+				}
+				return 0;
+			case SCSI_ABORT_SUCCESS:
+				/* We should have already aborted this one.  No
+				 * need to adjust timeout
+				 */
+				SCpnt->internal_timeout &= ~IN_ABORT;
+				return 0;
+			case SCSI_ABORT_NOT_RUNNING:
+				SCpnt->internal_timeout &= ~IN_ABORT;
+				update_timeout(SCpnt, 0);
+				return 0;
+			case SCSI_ABORT_ERROR:
+			default:
+				SCpnt->internal_timeout &= ~IN_ABORT;
+				return 1;
+			}
 		}
-		return 0;
-	    case SCSI_ABORT_SUCCESS:
-		/* We should have already aborted this one.  No
-		 * need to adjust timeout
-		 */
-                 SCpnt->internal_timeout &= ~IN_ABORT;
-                 return 0;
-	    case SCSI_ABORT_NOT_RUNNING:
-		SCpnt->internal_timeout &= ~IN_ABORT;
-		update_timeout(SCpnt, 0);
-		return 0;
-	    case SCSI_ABORT_ERROR:
-	    default:
-		SCpnt->internal_timeout &= ~IN_ABORT;
-		return 1;
-	    }
 	}
-    }
 }
 
 
 /* Mark a single SCSI Device as having been reset. */
 
-static inline void scsi_mark_device_reset(Scsi_Device *Device)
+static inline void scsi_mark_device_reset(Scsi_Device * Device)
 {
-  Device->was_reset = 1;
-  Device->expecting_cc_ua = 1;
+	Device->was_reset = 1;
+	Device->expecting_cc_ua = 1;
 }
 
 
@@ -820,14 +785,13 @@
 
 void scsi_mark_host_reset(struct Scsi_Host *Host)
 {
-  Scsi_Cmnd   * SCpnt;
-  Scsi_Device * SDpnt;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
 
-  for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
-    {
-      for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-        scsi_mark_device_reset(SCpnt->device);
-    }
+	for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+			scsi_mark_device_reset(SCpnt->device);
+	}
 }
 
 
@@ -835,251 +799,243 @@
 
 static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
 {
-  Scsi_Cmnd *SCpnt;
-  Scsi_Device * SDpnt;
+	Scsi_Cmnd *SCpnt;
+	Scsi_Device *SDpnt;
 
-  for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
-    {
-      for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
-        if (SCpnt->channel == channel)
-	  scsi_mark_device_reset(SCpnt->device);
-    }
+	for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+			if (SCpnt->channel == channel)
+				scsi_mark_device_reset(SCpnt->device);
+	}
 }
 
 
-static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+static int scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
-    int temp;
-    Scsi_Cmnd * SCpnt1;
-    Scsi_Device * SDpnt;
-    struct Scsi_Host * host = SCpnt->host;
+	int temp;
+	Scsi_Cmnd *SCpnt1;
+	Scsi_Device *SDpnt;
+	struct Scsi_Host *host = SCpnt->host;
 
-    printk("SCSI bus is being reset for host %d channel %d.\n",
-	   host->host_no, SCpnt->channel);
+	printk("SCSI bus is being reset for host %d channel %d.\n",
+	       host->host_no, SCpnt->channel);
 
 #if 0
-    /*
-     * First of all, we need to make a recommendation to the low-level
-     * driver as to whether a BUS_DEVICE_RESET should be performed,
-     * or whether we should do a full BUS_RESET.  There is no simple
-     * algorithm here - we basically use a series of heuristics
-     * to determine what we should do.
-     */
-    SCpnt->host->suggest_bus_reset = FALSE;
-
-    /*
-     * First see if all of the active devices on the bus have
-     * been jammed up so that we are attempting resets.  If so,
-     * then suggest a bus reset.  Forcing a bus reset could
-     * result in some race conditions, but no more than
-     * you would usually get with timeouts.  We will cross
-     * that bridge when we come to it.
-     *
-     * This is actually a pretty bad idea, since a sequence of
-     * commands will often timeout together and this will cause a
-     * Bus Device Reset followed immediately by a SCSI Bus Reset.
-     * If all of the active devices really are jammed up, the
-     * Bus Device Reset will quickly timeout and scsi_times_out
-     * will follow up with a SCSI Bus Reset anyway.
-     */
-    SCpnt1 = host->host_queue;
-    while(SCpnt1) {
-	if( SCpnt1->request.rq_status != RQ_INACTIVE
-	    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
-            	break;
-        SCpnt1 = SCpnt1->next;
- 	}
-    if( SCpnt1 == NULL ) {
-        reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
-    }
-
-    /*
-     * If the code that called us is suggesting a hard reset, then
-     * definitely request it.  This usually occurs because a
-     * BUS_DEVICE_RESET times out.
-     *
-     * Passing reset_flags along takes care of this automatically.
-     */
-    if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
-        SCpnt->host->suggest_bus_reset = TRUE;
-    }
-#endif
-
-    while (1) {
+	/*
+	 * First of all, we need to make a recommendation to the low-level
+	 * driver as to whether a BUS_DEVICE_RESET should be performed,
+	 * or whether we should do a full BUS_RESET.  There is no simple
+	 * algorithm here - we basically use a series of heuristics
+	 * to determine what we should do.
+	 */
+	SCpnt->host->suggest_bus_reset = FALSE;
 
 	/*
-	 * Protect against races here.  If the command is done, or we are
-	 * on a different command forget it.
+	 * First see if all of the active devices on the bus have
+	 * been jammed up so that we are attempting resets.  If so,
+	 * then suggest a bus reset.  Forcing a bus reset could
+	 * result in some race conditions, but no more than
+	 * you would usually get with timeouts.  We will cross
+	 * that bridge when we come to it.
+	 *
+	 * This is actually a pretty bad idea, since a sequence of
+	 * commands will often timeout together and this will cause a
+	 * Bus Device Reset followed immediately by a SCSI Bus Reset.
+	 * If all of the active devices really are jammed up, the
+	 * Bus Device Reset will quickly timeout and scsi_times_out
+	 * will follow up with a SCSI Bus Reset anyway.
 	 */
-	if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
-	  if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
-	    return 0;
-	  }
-
-	if (SCpnt->internal_timeout & IN_RESET)
-	{
-	    spin_unlock_irq(&io_request_lock);
-	    while (SCpnt->internal_timeout & IN_RESET)
-		barrier();
-	    spin_lock_irq(&io_request_lock);
+	SCpnt1 = host->host_queue;
+	while (SCpnt1) {
+		if (SCpnt1->request.rq_status != RQ_INACTIVE
+		    && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0)
+			break;
+		SCpnt1 = SCpnt1->next;
 	}
-	else
-	{
-	    SCpnt->internal_timeout |= IN_RESET;
-	    update_timeout(SCpnt, RESET_TIMEOUT);
-
-	    if (reset_flags & SCSI_RESET_SYNCHRONOUS)
-	      SCpnt->flags |= SYNC_RESET;
-	    if (host->host_busy)
-	    {
-                for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
-                {
-                    SCpnt1 = SDpnt->device_queue;
-                    while(SCpnt1) {
-                        if (SCpnt1->request.rq_status != RQ_INACTIVE) {
-#if 0
-                            if (!(SCpnt1->flags & IS_RESETTING) &&
-                                !(SCpnt1->internal_timeout & IN_ABORT))
-                                scsi_abort(SCpnt1, DID_RESET);
-#endif
-                            SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
-                        }
-                        SCpnt1 = SCpnt1->next;
-                    }
-                }
+	if (SCpnt1 == NULL) {
+		reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
+	}
+	/*
+	 * If the code that called us is suggesting a hard reset, then
+	 * definitely request it.  This usually occurs because a
+	 * BUS_DEVICE_RESET times out.
+	 *
+	 * Passing reset_flags along takes care of this automatically.
+	 */
+	if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) {
+		SCpnt->host->suggest_bus_reset = TRUE;
+	}
+#endif
+
+	while (1) {
 
-		host->last_reset = jiffies;
-		host->resetting = 1;
-		/*
-		 * I suppose that the host reset callback will not play
-		 * with the resetting field. We have just set the resetting
-		 * flag here. -arca
-		 */
-		temp = host->hostt->reset(SCpnt, reset_flags);
-		/*
-		  This test allows the driver to introduce an additional bus
-		  settle time delay by setting last_reset up to 20 seconds in
-		  the future.  In the normal case where the driver does not
-		  modify last_reset, it must be assumed that the actual bus
-		  reset occurred immediately prior to the return to this code,
-		  and so last_reset must be updated to the current time, so
-		  that the delay in internal_cmnd will guarantee at least a
-		  MIN_RESET_DELAY bus settle time.
-		*/
-		if (host->last_reset - jiffies > 20UL * HZ)
-		  host->last_reset = jiffies;
-	    }
-	    else
-	    {
-		if (!host->block) host->host_busy++;
-		host->last_reset = jiffies;
-		host->resetting = 1;
-		SCpnt->flags |= (WAS_RESET | IS_RESETTING);
 		/*
-		 * I suppose that the host reset callback will not play
-		 * with the resetting field. We have just set the resetting
-		 * flag here. -arca
+		 * Protect against races here.  If the command is done, or we are
+		 * on a different command forget it.
 		 */
-		temp = host->hostt->reset(SCpnt, reset_flags);
-		if (time_before(host->last_reset, jiffies) ||
-		    (time_after(host->last_reset, jiffies + 20 * HZ)))
-		  host->last_reset = jiffies;
-		if (!host->block) host->host_busy--;
-	    }
-	    if (reset_flags & SCSI_RESET_SYNCHRONOUS)
-	      SCpnt->flags &= ~SYNC_RESET;
+		if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
+			if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+				return 0;
+			}
+		if (SCpnt->internal_timeout & IN_RESET) {
+			spin_unlock_irq(&io_request_lock);
+			while (SCpnt->internal_timeout & IN_RESET)
+				barrier();
+			spin_lock_irq(&io_request_lock);
+		} else {
+			SCpnt->internal_timeout |= IN_RESET;
+			update_timeout(SCpnt, RESET_TIMEOUT);
+
+			if (reset_flags & SCSI_RESET_SYNCHRONOUS)
+				SCpnt->flags |= SYNC_RESET;
+			if (host->host_busy) {
+				for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+					SCpnt1 = SDpnt->device_queue;
+					while (SCpnt1) {
+						if (SCpnt1->request.rq_status != RQ_INACTIVE) {
+#if 0
+							if (!(SCpnt1->flags & IS_RESETTING) &&
+							    !(SCpnt1->internal_timeout & IN_ABORT))
+								scsi_abort(SCpnt1, DID_RESET);
+#endif
+							SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
+						}
+						SCpnt1 = SCpnt1->next;
+					}
+				}
+
+				host->last_reset = jiffies;
+				host->resetting = 1;
+				/*
+				 * I suppose that the host reset callback will not play
+				 * with the resetting field. We have just set the resetting
+				 * flag here. -arca
+				 */
+				temp = host->hostt->reset(SCpnt, reset_flags);
+				/*
+				   This test allows the driver to introduce an additional bus
+				   settle time delay by setting last_reset up to 20 seconds in
+				   the future.  In the normal case where the driver does not
+				   modify last_reset, it must be assumed that the actual bus
+				   reset occurred immediately prior to the return to this code,
+				   and so last_reset must be updated to the current time, so
+				   that the delay in internal_cmnd will guarantee at least a
+				   MIN_RESET_DELAY bus settle time.
+				 */
+				if (host->last_reset - jiffies > 20UL * HZ)
+					host->last_reset = jiffies;
+			} else {
+				if (!host->block)
+					host->host_busy++;
+				host->last_reset = jiffies;
+				host->resetting = 1;
+				SCpnt->flags |= (WAS_RESET | IS_RESETTING);
+				/*
+				 * I suppose that the host reset callback will not play
+				 * with the resetting field. We have just set the resetting
+				 * flag here. -arca
+				 */
+				temp = host->hostt->reset(SCpnt, reset_flags);
+				if (time_before(host->last_reset, jiffies) ||
+				    (time_after(host->last_reset, jiffies + 20 * HZ)))
+					host->last_reset = jiffies;
+				if (!host->block)
+					host->host_busy--;
+			}
+			if (reset_flags & SCSI_RESET_SYNCHRONOUS)
+				SCpnt->flags &= ~SYNC_RESET;
 
 #ifdef DEBUG
-	    printk("scsi reset function returned %d\n", temp);
+			printk("scsi reset function returned %d\n", temp);
 #endif
 
-            /*
-             * Now figure out what we need to do, based upon
-             * what the low level driver said that it did.
-	     * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
-	     * or SCSI_RESET_WAKEUP, then the low level driver did a
-	     * bus device reset or bus reset, so we should go through
-	     * and mark one or all of the devices on that bus
-	     * as having been reset.
-             */
-            switch(temp & SCSI_RESET_ACTION) {
-	    case SCSI_RESET_SUCCESS:
-	        if (temp & SCSI_RESET_HOST_RESET)
-		  scsi_mark_host_reset(host);
-	        else if (temp & SCSI_RESET_BUS_RESET)
-		  scsi_mark_bus_reset(host, SCpnt->channel);
-		else scsi_mark_device_reset(SCpnt->device);
-		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-		return 0;
-	    case SCSI_RESET_PENDING:
-	        if (temp & SCSI_RESET_HOST_RESET)
-		  scsi_mark_host_reset(host);
-	        else if (temp & SCSI_RESET_BUS_RESET)
-		  scsi_mark_bus_reset(host, SCpnt->channel);
-		else scsi_mark_device_reset(SCpnt->device);
-	    case SCSI_RESET_NOT_RUNNING:
-		return 0;
-	    case SCSI_RESET_PUNT:
-		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-                scsi_request_sense (SCpnt);
-                return 0;
-	    case SCSI_RESET_WAKEUP:
-	        if (temp & SCSI_RESET_HOST_RESET)
-		  scsi_mark_host_reset(host);
-	        else if (temp & SCSI_RESET_BUS_RESET)
-		  scsi_mark_bus_reset(host, SCpnt->channel);
-		else scsi_mark_device_reset(SCpnt->device);
-		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-		scsi_request_sense (SCpnt);
-                /*
-                 * If a bus reset was performed, we
-                 * need to wake up each and every command
-                 * that was active on the bus or if it was a HBA
-                 * reset all active commands on all channels
-                 */
-                if( temp & SCSI_RESET_HOST_RESET )
-                {
-                    for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
-                    {
-                        SCpnt1 = SDpnt->device_queue;
-                        while(SCpnt1) {
-                            if (SCpnt1->request.rq_status != RQ_INACTIVE
-                                && SCpnt1 != SCpnt)
-                                scsi_request_sense (SCpnt1);
-                            SCpnt1 = SCpnt1->next;
-                        }
-                    }
-                } else if( temp & SCSI_RESET_BUS_RESET ) {
-                    for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
-                    {
-                        SCpnt1 = SDpnt->device_queue;
-                        while(SCpnt1) {
-                            if(SCpnt1->request.rq_status != RQ_INACTIVE
-                               && SCpnt1 != SCpnt
-                               && SCpnt1->channel == SCpnt->channel)
-                                scsi_request_sense (SCpnt);
-                            SCpnt1 = SCpnt1->next;
-                        }
-                    }
-                }
-		return 0;
-	    case SCSI_RESET_SNOOZE:
-		/* In this case, we set the timeout field to 0
-		 * so that this command does not time out any more,
-		 * and we return 1 so that we get a message on the
-		 * screen.
-		 */
-		SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
-		update_timeout(SCpnt, 0);
-		/* If you snooze, you lose... */
-	    case SCSI_RESET_ERROR:
-	    default:
-		return 1;
-	    }
+			/*
+			 * Now figure out what we need to do, based upon
+			 * what the low level driver said that it did.
+			 * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
+			 * or SCSI_RESET_WAKEUP, then the low level driver did a
+			 * bus device reset or bus reset, so we should go through
+			 * and mark one or all of the devices on that bus
+			 * as having been reset.
+			 */
+			switch (temp & SCSI_RESET_ACTION) {
+			case SCSI_RESET_SUCCESS:
+				if (temp & SCSI_RESET_HOST_RESET)
+					scsi_mark_host_reset(host);
+				else if (temp & SCSI_RESET_BUS_RESET)
+					scsi_mark_bus_reset(host, SCpnt->channel);
+				else
+					scsi_mark_device_reset(SCpnt->device);
+				SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3);
+				return 0;
+			case SCSI_RESET_PENDING:
+				if (temp & SCSI_RESET_HOST_RESET)
+					scsi_mark_host_reset(host);
+				else if (temp & SCSI_RESET_BUS_RESET)
+					scsi_mark_bus_reset(host, SCpnt->channel);
+				else
+					scsi_mark_device_reset(SCpnt->device);
+			case SCSI_RESET_NOT_RUNNING:
+				return 0;
+			case SCSI_RESET_PUNT:
+				SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3);
+				scsi_request_sense(SCpnt);
+				return 0;
+			case SCSI_RESET_WAKEUP:
+				if (temp & SCSI_RESET_HOST_RESET)
+					scsi_mark_host_reset(host);
+				else if (temp & SCSI_RESET_BUS_RESET)
+					scsi_mark_bus_reset(host, SCpnt->channel);
+				else
+					scsi_mark_device_reset(SCpnt->device);
+				SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3);
+				scsi_request_sense(SCpnt);
+				/*
+				 * If a bus reset was performed, we
+				 * need to wake up each and every command
+				 * that was active on the bus or if it was a HBA
+				 * reset all active commands on all channels
+				 */
+				if (temp & SCSI_RESET_HOST_RESET) {
+					for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+						SCpnt1 = SDpnt->device_queue;
+						while (SCpnt1) {
+							if (SCpnt1->request.rq_status != RQ_INACTIVE
+							    && SCpnt1 != SCpnt)
+								scsi_request_sense(SCpnt1);
+							SCpnt1 = SCpnt1->next;
+						}
+					}
+				} else if (temp & SCSI_RESET_BUS_RESET) {
+					for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+						SCpnt1 = SDpnt->device_queue;
+						while (SCpnt1) {
+							if (SCpnt1->request.rq_status != RQ_INACTIVE
+							&& SCpnt1 != SCpnt
+							    && SCpnt1->channel == SCpnt->channel)
+								scsi_request_sense(SCpnt);
+							SCpnt1 = SCpnt1->next;
+						}
+					}
+				}
+				return 0;
+			case SCSI_RESET_SNOOZE:
+				/* In this case, we set the timeout field to 0
+				 * so that this command does not time out any more,
+				 * and we return 1 so that we get a message on the
+				 * screen.
+				 */
+				SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2 | IN_RESET3);
+				update_timeout(SCpnt, 0);
+				/* If you snooze, you lose... */
+			case SCSI_RESET_ERROR:
+			default:
+				return 1;
+			}
 
-	    return temp;
+			return temp;
+		}
 	}
-    }
 }
 
 /*
@@ -1092,32 +1048,26 @@
 
 int update_timeout(Scsi_Cmnd * SCset, int timeout)
 {
-  int	rtn;
+	int rtn;
 
-  /*
-   * We are using the new error handling code to actually register/deregister
-   * timers for timeout.
-   */
-
-  if( !timer_pending(&SCset->eh_timeout) )
-    {
-      rtn = 0;
-    }
-  else
-    {
-      rtn = SCset->eh_timeout.expires - jiffies;
-    }
-
-  if( timeout == 0 )
-    {
-      scsi_delete_timer(SCset);
-    }
-  else
-    {
-      scsi_add_timer(SCset, timeout, scsi_old_times_out);
-    }
+	/*
+	 * We are using the new error handling code to actually register/deregister
+	 * timers for timeout.
+	 */
+
+	if (!timer_pending(&SCset->eh_timeout)) {
+		rtn = 0;
+	} else {
+		rtn = SCset->eh_timeout.expires - jiffies;
+	}
+
+	if (timeout == 0) {
+		scsi_delete_timer(SCset);
+	} else {
+		scsi_add_timer(SCset, timeout, scsi_old_times_out);
+	}
 
-  return rtn;
+	return rtn;
 }
 
 
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_obsolete.h linux/drivers/scsi/scsi_obsolete.h
--- v2.3.16/linux/drivers/scsi/scsi_obsolete.h	Sun Dec 21 17:04:49 1997
+++ linux/drivers/scsi/scsi_obsolete.h	Sat Sep  4 10:48:46 1999
@@ -17,7 +17,7 @@
 
 /* We did not do anything.  
  * Wait some more for this command to complete, and if this does not work, 
- * try something more serious. */ 
+ * try something more serious. */
 #define SCSI_ABORT_SNOOZE 0
 
 /* This means that we were able to abort the command.  We have already
@@ -103,4 +103,4 @@
  */
 #define SCSI_RESET_ACTION   0xff
 
-#endif /* SCSI_OBSOLETE_H */
+#endif				/* SCSI_OBSOLETE_H */
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c
--- v2.3.16/linux/drivers/scsi/scsi_proc.c	Wed Jun  9 16:59:16 1999
+++ linux/drivers/scsi/scsi_proc.c	Sat Sep  4 10:48:46 1999
@@ -16,7 +16,7 @@
  * Michael A. Griffith <grif@acm.org>
  */
 
-#include <linux/config.h> /* for CONFIG_PROC_FS */
+#include <linux/config.h>	/* for CONFIG_PROC_FS */
 #define __NO_VERSION__
 #include <linux/module.h>
 
@@ -37,284 +37,275 @@
 
 #ifdef CONFIG_PROC_FS
 extern int scsi_proc_info(char *, char **, off_t, int, int, int);
- 
+
 struct scsi_dir {
-    struct proc_dir_entry entry;
-    char name[4];
+	struct proc_dir_entry entry;
+	char name[4];
 };
 
 
 /* generic_proc_info
  * Used if the driver currently has no own support for /proc/scsi
  */
-int generic_proc_info(char *buffer, char **start, off_t offset, 
-		     int length, int inode, int inout, 
-                     const char *(*info)(struct Scsi_Host *),
-                     struct Scsi_Host *sh)
+int generic_proc_info(char *buffer, char **start, off_t offset,
+		      int length, int inode, int inout,
+		      const char *(*info) (struct Scsi_Host *),
+		      struct Scsi_Host *sh)
 {
-    int len, pos, begin;
+	int len, pos, begin;
+
+	if (inout == TRUE)
+		return (-ENOSYS);	/* This is a no-op */
+
+	begin = 0;
+	if (info && sh) {
+		pos = len = sprintf(buffer, "%s\n", info(sh));
+	} else {
+		pos = len = sprintf(buffer,
+			"The driver does not yet support the proc-fs\n");
+	}
+	if (pos < offset) {
+		len = 0;
+		begin = pos;
+	}
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);
+	if (len > length)
+		len = length;
 
-    if(inout == TRUE)
-	return(-ENOSYS);  /* This is a no-op */
-    
-    begin = 0;
-    if (info && sh) {
-          pos = len = sprintf(buffer, "%s\n", info(sh));
-    }
-    else {
-      pos = len = sprintf(buffer, 
-                          "The driver does not yet support the proc-fs\n");
-    }
-    if(pos < offset) {
-	len = 0;
-	begin = pos;
-    }
-    
-    *start = buffer + (offset - begin);   /* Start of wanted data */
-    len -= (offset - begin);
-    if(len > length)
-	len = length;
-    
-    return(len);
+	return (len);
 }
 
 /* dispatch_scsi_info is the central dispatcher 
  * It is the interface between the proc-fs and the SCSI subsystem code
  */
-extern int dispatch_scsi_info(int ino, char *buffer, char **start, 
+extern int dispatch_scsi_info(int ino, char *buffer, char **start,
 			      off_t offset, int length, int func)
 {
-    struct Scsi_Host *hpnt = scsi_hostlist;
-    
-    if(ino == PROC_SCSI_SCSI) {            
-        /*
-         * This is for the scsi core, rather than any specific
-         * lowlevel driver.
-         */
-        return(scsi_proc_info(buffer, start, offset, length, 0, func));
-    }
-    
-    while(hpnt) {
-        if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
-            if(hpnt->hostt->proc_info == NULL)
-                return generic_proc_info(buffer, start, offset, length, 
-                                         hpnt->host_no, func,
-                                         hpnt->hostt->info,
-                                         hpnt);
-            else
-                return(hpnt->hostt->proc_info(buffer, start, offset, 
-                                              length, hpnt->host_no, func));
-        }
-        hpnt = hpnt->next;
-    }
-    return(-EBADF);
+	struct Scsi_Host *hpnt = scsi_hostlist;
+
+	if (ino == PROC_SCSI_SCSI) {
+		/*
+		 * This is for the scsi core, rather than any specific
+		 * lowlevel driver.
+		 */
+		return (scsi_proc_info(buffer, start, offset, length, 0, func));
+	}
+	while (hpnt) {
+		if (ino == (hpnt->host_no + PROC_SCSI_FILE)) {
+			if (hpnt->hostt->proc_info == NULL)
+				return generic_proc_info(buffer, start, offset, length,
+						     hpnt->host_no, func,
+						       hpnt->hostt->info,
+							 hpnt);
+			else
+				return (hpnt->hostt->proc_info(buffer, start, offset,
+					   length, hpnt->host_no, func));
+		}
+		hpnt = hpnt->next;
+	}
+	return (-EBADF);
 }
 
 static void scsi_proc_fill_inode(struct inode *inode, int fill)
 {
-Scsi_Host_Template *shpnt;
+	Scsi_Host_Template *shpnt;
 
-shpnt = scsi_hosts;
-while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino)
-    shpnt = shpnt->next;
-if (!shpnt || !shpnt->module)
-    return;
-if (fill)
-    __MOD_INC_USE_COUNT(shpnt->module);
-else
-    __MOD_DEC_USE_COUNT(shpnt->module);
+	shpnt = scsi_hosts;
+	while (shpnt && shpnt->proc_dir->low_ino != inode->i_ino)
+		shpnt = shpnt->next;
+	if (!shpnt || !shpnt->module)
+		return;
+	if (fill)
+		__MOD_INC_USE_COUNT(shpnt->module);
+	else
+		__MOD_DEC_USE_COUNT(shpnt->module);
 }
 
-void build_proc_dir_entries(Scsi_Host_Template *tpnt)
+void build_proc_dir_entries(Scsi_Host_Template * tpnt)
 {
-    struct Scsi_Host *hpnt;
-    struct scsi_dir *scsi_hba_dir;
+	struct Scsi_Host *hpnt;
+	struct scsi_dir *scsi_hba_dir;
 
-    proc_scsi_register(0, tpnt->proc_dir);
-    tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode;
+	proc_scsi_register(0, tpnt->proc_dir);
+	tpnt->proc_dir->fill_inode = &scsi_proc_fill_inode;
 
-    hpnt = scsi_hostlist;
-    while (hpnt) {
-        if (tpnt == hpnt->hostt) {
-            scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL);
-            if(scsi_hba_dir == NULL)
-                panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
-            memset(scsi_hba_dir, 0, sizeof(struct scsi_dir));
-            scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no;
-            scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name,"%d",
-                                                    hpnt->host_no);
-            scsi_hba_dir->entry.name = scsi_hba_dir->name;
-            scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR;
-            proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry);
-        }
-        hpnt = hpnt->next;
-    }
+	hpnt = scsi_hostlist;
+	while (hpnt) {
+		if (tpnt == hpnt->hostt) {
+			scsi_hba_dir = scsi_init_malloc(sizeof(struct scsi_dir), GFP_KERNEL);
+			if (scsi_hba_dir == NULL)
+				panic("Not enough memory to register SCSI HBA in /proc/scsi !\n");
+			memset(scsi_hba_dir, 0, sizeof(struct scsi_dir));
+			scsi_hba_dir->entry.low_ino = PROC_SCSI_FILE + hpnt->host_no;
+			scsi_hba_dir->entry.namelen = sprintf(scsi_hba_dir->name, "%d",
+							  hpnt->host_no);
+			scsi_hba_dir->entry.name = scsi_hba_dir->name;
+			scsi_hba_dir->entry.mode = S_IFREG | S_IRUGO | S_IWUSR;
+			proc_scsi_register(tpnt->proc_dir, &scsi_hba_dir->entry);
+		}
+		hpnt = hpnt->next;
+	}
 }
 
 /*
  *  parseHandle *parseInit(char *buf, char *cmdList, int cmdNum); 
- *	 	gets a pointer to a null terminated data buffer
- *		and a list of commands with blanks as delimiter 
+ *              gets a pointer to a null terminated data buffer
+ *              and a list of commands with blanks as delimiter 
  *      in between. 
  *      The commands have to be alphanumerically sorted. 
  *      cmdNum has to contain the number of commands.
- *		On success, a pointer to a handle structure
- *		is returned, NULL on failure
+ *              On success, a pointer to a handle structure
+ *              is returned, NULL on failure
  *
- *	int parseOpt(parseHandle *handle, char **param);
- *		processes the next parameter. On success, the
- *		index of the appropriate command in the cmdList
- *		is returned, starting with zero.
- *		param points to the null terminated parameter string.
- *		On failure, -1 is returned.
+ *      int parseOpt(parseHandle *handle, char **param);
+ *              processes the next parameter. On success, the
+ *              index of the appropriate command in the cmdList
+ *              is returned, starting with zero.
+ *              param points to the null terminated parameter string.
+ *              On failure, -1 is returned.
  *
- *	The databuffer buf may only contain pairs of commands
- *	    options, separated by blanks:
- *		<Command> <Parameter> [<Command> <Parameter>]*
+ *      The databuffer buf may only contain pairs of commands
+ *          options, separated by blanks:
+ *              <Command> <Parameter> [<Command> <Parameter>]*
  */
 
-typedef struct
-{
-    char *buf,				   /* command buffer  */
-	 *cmdList,                         /* command list    */
-	 *bufPos,                          /* actual position */
-	 **cmdPos,                         /* cmdList index   */
-	 cmdNum;                           /* cmd number      */
+typedef struct {
+	char *buf,		/* command buffer  */
+	*cmdList,		/* command list    */
+	*bufPos,		/* actual position */
+	**cmdPos,		/* cmdList index   */
+	 cmdNum;		/* cmd number      */
 } parseHandle;
-	
 
-inline int parseFree (parseHandle *handle)               /* free memory     */
-{
-    kfree (handle->cmdPos);
-    kfree (handle);
-    
-    return(-1);
+
+inline int parseFree(parseHandle * handle)
+{				/* free memory     */
+	kfree(handle->cmdPos);
+	kfree(handle);
+
+	return (-1);
 }
 
-	
+
 parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
 {
-    char        *ptr;                               /* temp pointer    */
-    parseHandle *handle;                            /* new handle      */
-    
-    if (!buf || !cmdList)                           /* bad input ?     */
-	return(NULL);
-    if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0)
-	return(NULL);                               /* out of memory   */
-    if ((handle->cmdPos = (char**) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) {
-	kfree(handle);
-	return(NULL);                               /* out of memory   */
-    }
-    
-    handle->buf     = handle->bufPos = buf;         /* init handle     */
-    handle->cmdList = cmdList;
-    handle->cmdNum  = cmdNum;
-    
-    handle->cmdPos[cmdNum = 0] = cmdList;
-    for (ptr = cmdList; *ptr; ptr++) {          /* scan command string */
-	if(*ptr == ' ') {                       /* and insert zeroes   */
-	    *ptr++ = 0;
-	    handle->cmdPos[++cmdNum] = ptr++;
-	} 
-    }
-    return(handle);
+	char *ptr;		/* temp pointer    */
+	parseHandle *handle;	/* new handle      */
+
+	if (!buf || !cmdList)	/* bad input ?     */
+		return (NULL);
+	if ((handle = (parseHandle *) kmalloc(sizeof(parseHandle), GFP_KERNEL)) == 0)
+		return (NULL);	/* out of memory   */
+	if ((handle->cmdPos = (char **) kmalloc(sizeof(int) * cmdNum, GFP_KERNEL)) == 0) {
+		kfree(handle);
+		return (NULL);	/* out of memory   */
+	}
+	handle->buf = handle->bufPos = buf;	/* init handle     */
+	handle->cmdList = cmdList;
+	handle->cmdNum = cmdNum;
+
+	handle->cmdPos[cmdNum = 0] = cmdList;
+	for (ptr = cmdList; *ptr; ptr++) {	/* scan command string */
+		if (*ptr == ' ') {	/* and insert zeroes   */
+			*ptr++ = 0;
+			handle->cmdPos[++cmdNum] = ptr++;
+		}
+	}
+	return (handle);
 }
 
 
-int parseOpt(parseHandle *handle, char **param)
+int parseOpt(parseHandle * handle, char **param)
 {
-    int  cmdIndex = 0, 
-	 cmdLen = 0;
-    char *startPos;
-    
-    if (!handle)                                    /* invalid handle  */
-	return(parseFree(handle));
-    /* skip spaces     */  
-    for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
-    if (!*(handle->bufPos))
-	return(parseFree(handle));                  /* end of data     */
-    
-    startPos = handle->bufPos;                      /* store cmd start */
-    for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++)
-    {                                               /* no string end?  */
-	for (;;)
-	{
-	    if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
-		break;                              /* char matches ?  */
-	    else
-		if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen))
-		    return(parseFree(handle));      /* unknown command */
-	    
-	    if (cmdIndex >= handle->cmdNum)
-		return(parseFree(handle));          /* unknown command */     
-	}
-	
-	cmdLen++;                                   /* next char       */
-    }
-    
-    /* Get param. First skip all blanks, then insert zero after param  */
-    
-    for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
-    *param = handle->bufPos; 
-    
-    for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
-    *(handle->bufPos++) = 0;
-    
-    return(cmdIndex);
+	int cmdIndex = 0, cmdLen = 0;
+	char *startPos;
+
+	if (!handle)		/* invalid handle  */
+		return (parseFree(handle));
+	/* skip spaces     */
+	for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
+	if (!*(handle->bufPos))
+		return (parseFree(handle));	/* end of data     */
+
+	startPos = handle->bufPos;	/* store cmd start */
+	for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++) {	/* no string end?  */
+		for (;;) {
+			if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
+				break;	/* char matches ?  */
+			else if (memcmp(startPos, (char *) (handle->cmdPos[++cmdIndex]), cmdLen))
+				return (parseFree(handle));	/* unknown command */
+
+			if (cmdIndex >= handle->cmdNum)
+				return (parseFree(handle));	/* unknown command */
+		}
+
+		cmdLen++;	/* next char       */
+	}
+
+	/* Get param. First skip all blanks, then insert zero after param  */
+
+	for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
+	*param = handle->bufPos;
+
+	for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
+	*(handle->bufPos++) = 0;
+
+	return (cmdIndex);
 }
 
-void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
-{	    
-  
-    int x, y = *size;
-    extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
-        
-    y = sprintf(buffer + len, 
-		    "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
+void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
+{
+
+	int x, y = *size;
+	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+
+	y = sprintf(buffer + len,
+	     "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
 		    scd->host->host_no, scd->channel, scd->id, scd->lun);
-    for (x = 0; x < 8; x++) {
-	if (scd->vendor[x] >= 0x20)
-	    y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
-	else
-	    y += sprintf(buffer + len + y," ");
-    }
-    y += sprintf(buffer + len + y, " Model: ");
-    for (x = 0; x < 16; x++) {
-	if (scd->model[x] >= 0x20)
-	    y +=  sprintf(buffer + len + y, "%c", scd->model[x]);
-	else
-	    y += sprintf(buffer + len + y, " ");
-    }
-    y += sprintf(buffer + len + y, " Rev: ");
-    for (x = 0; x < 4; x++) {
-	if (scd->rev[x] >= 0x20)
-	    y += sprintf(buffer + len + y, "%c", scd->rev[x]);
-	else
-	    y += sprintf(buffer + len + y, " ");
-    }
-    y += sprintf(buffer + len + y, "\n");
-    
-    y += sprintf(buffer + len + y, "  Type:   %s ",
-		     scd->type < MAX_SCSI_DEVICE_CODE ? 
-		     scsi_device_types[(int)scd->type] : "Unknown          " );
-    y += sprintf(buffer + len + y, "               ANSI"
-		     " SCSI revision: %02x", (scd->scsi_level - 1)?scd->scsi_level - 1:1);
-    if (scd->scsi_level == 2)
-	y += sprintf(buffer + len + y, " CCS\n");
-    else
+	for (x = 0; x < 8; x++) {
+		if (scd->vendor[x] >= 0x20)
+			y += sprintf(buffer + len + y, "%c", scd->vendor[x]);
+		else
+			y += sprintf(buffer + len + y, " ");
+	}
+	y += sprintf(buffer + len + y, " Model: ");
+	for (x = 0; x < 16; x++) {
+		if (scd->model[x] >= 0x20)
+			y += sprintf(buffer + len + y, "%c", scd->model[x]);
+		else
+			y += sprintf(buffer + len + y, " ");
+	}
+	y += sprintf(buffer + len + y, " Rev: ");
+	for (x = 0; x < 4; x++) {
+		if (scd->rev[x] >= 0x20)
+			y += sprintf(buffer + len + y, "%c", scd->rev[x]);
+		else
+			y += sprintf(buffer + len + y, " ");
+	}
 	y += sprintf(buffer + len + y, "\n");
 
-    *size = y; 
-    return;
+	y += sprintf(buffer + len + y, "  Type:   %s ",
+		     scd->type < MAX_SCSI_DEVICE_CODE ?
+	       scsi_device_types[(int) scd->type] : "Unknown          ");
+	y += sprintf(buffer + len + y, "               ANSI"
+		     " SCSI revision: %02x", (scd->scsi_level - 1) ? scd->scsi_level - 1 : 1);
+	if (scd->scsi_level == 2)
+		y += sprintf(buffer + len + y, " CCS\n");
+	else
+		y += sprintf(buffer + len + y, "\n");
+
+	*size = y;
+	return;
 }
 
 #else
 
-void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
+void proc_print_scsidevice(Scsi_Device * scd, char *buffer, int *size, int len)
 {
 }
 
-#endif /* CONFIG_PROC_FS */
+#endif				/* CONFIG_PROC_FS */
 
 /*
  * Overrides for Emacs so that we get a uniform tabbing style.
@@ -334,4 +325,3 @@
  * tab-width: 8
  * End:
  */
-
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsi_queue.c linux/drivers/scsi/scsi_queue.c
--- v2.3.16/linux/drivers/scsi/scsi_queue.c	Mon Jul 27 18:22:12 1998
+++ linux/drivers/scsi/scsi_queue.c	Sat Sep  4 10:48:46 1999
@@ -39,19 +39,19 @@
 
 /*
  * TODO:
- *	1) Prevent multiple traversals of list to look for commands to
- *	   queue.
- *	2) Protect against multiple insertions of list at the same time.
+ *      1) Prevent multiple traversals of list to look for commands to
+ *         queue.
+ *      2) Protect against multiple insertions of list at the same time.
  * DONE:
- *	1) Set state of scsi command to a new state value for ml queue.
- *	2) Insert into queue when host rejects command.
- *	3) Make sure status code is properly passed from low-level queue func
- *	   so that internal_cmnd properly returns the right value.
- *	4) Insert into queue when QUEUE_FULL.
- *	5) Cull queue in bottom half handler.
- *	6) Check usage count prior to queue insertion.  Requeue if usage
- *	   count is 0.
- *	7) Don't send down any more commands if the host/device is busy.
+ *      1) Set state of scsi command to a new state value for ml queue.
+ *      2) Insert into queue when host rejects command.
+ *      3) Make sure status code is properly passed from low-level queue func
+ *         so that internal_cmnd properly returns the right value.
+ *      4) Insert into queue when QUEUE_FULL.
+ *      5) Cull queue in bottom half handler.
+ *      6) Check usage count prior to queue insertion.  Requeue if usage
+ *         count is 0.
+ *      7) Don't send down any more commands if the host/device is busy.
  */
 
 static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $";
@@ -61,8 +61,9 @@
  * same time.  FIXME(eric) - there should be separate spinlocks for each host.
  * This will reduce contention.
  */
-spinlock_t	scsi_mlqueue_lock        = SPIN_LOCK_UNLOCKED;
-spinlock_t	scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED;
+
+spinlock_t scsi_mlqueue_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  * Function:    scsi_mlqueue_insert()
@@ -70,127 +71,110 @@
  * Purpose:     Insert a command in the midlevel queue.
  *
  * Arguments:   cmd    - command that we are adding to queue.
- *		reason - why we are inserting command to queue.
+ *              reason - why we are inserting command to queue.
  *
  * Returns:     Nothing.
  *
- * Notes:	We do this for one of two cases.  Either the host is busy
- *		and it cannot accept any more commands for the time being,
- *		or the device returned QUEUE_FULL and can accept no more
- *		commands.
- * Notes:	This could be called either from an interrupt context or a
- *		normal process context.
+ * Notes:       We do this for one of two cases.  Either the host is busy
+ *              and it cannot accept any more commands for the time being,
+ *              or the device returned QUEUE_FULL and can accept no more
+ *              commands.
+ * Notes:       This could be called either from an interrupt context or a
+ *              normal process context.
  */
-int
-scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
+int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
 {
-    Scsi_Cmnd        * cpnt;
-    unsigned long      flags;
-    struct Scsi_Host * host;
-
-    SCSI_LOG_MLQUEUE(1,printk("Inserting command %p into mlqueue\n", cmd));
-
-    /*
-     * We are inserting the command into the ml queue.  First, we
-     * cancel the timer, so it doesn't time out.
-     */
-    scsi_delete_timer(cmd);
-
-    host = cmd->host;
-
-    /*
-     * Next, set the appropriate busy bit for the device/host.
-     */
-    if( reason == SCSI_MLQUEUE_HOST_BUSY )
-    {
-	/*
-	 * Protect against race conditions.  If the host isn't busy,
-	 * assume that something actually completed, and that we should
-	 * be able to queue a command now.  Note that there is an implicit
-	 * assumption that every host can always queue at least one command.
-	 * If a host is inactive and cannot queue any commands, I don't see
-	 * how things could possibly work anyways.
-	 */
-	if( host->host_busy == 0 )
-	{
-	    if( scsi_retry_command(cmd) == 0 )
-	    {
-		return 0;
-	    }
+	Scsi_Cmnd *cpnt;
+	unsigned long flags;
+	struct Scsi_Host *host;
+
+	SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd));
+
+	/*
+	 * We are inserting the command into the ml queue.  First, we
+	 * cancel the timer, so it doesn't time out.
+	 */
+	scsi_delete_timer(cmd);
+
+	host = cmd->host;
+
+	/*
+	 * Next, set the appropriate busy bit for the device/host.
+	 */
+	if (reason == SCSI_MLQUEUE_HOST_BUSY) {
+		/*
+		 * Protect against race conditions.  If the host isn't busy,
+		 * assume that something actually completed, and that we should
+		 * be able to queue a command now.  Note that there is an implicit
+		 * assumption that every host can always queue at least one command.
+		 * If a host is inactive and cannot queue any commands, I don't see
+		 * how things could possibly work anyways.
+		 */
+		if (host->host_busy == 0) {
+			if (scsi_retry_command(cmd) == 0) {
+				return 0;
+			}
+		}
+		host->host_blocked = TRUE;
+		cmd->host_wait = TRUE;
+	} else {
+		/*
+		 * Protect against race conditions.  If the device isn't busy,
+		 * assume that something actually completed, and that we should
+		 * be able to queue a command now.  Note that there is an implicit
+		 * assumption that every host can always queue at least one command.
+		 * If a host is inactive and cannot queue any commands, I don't see
+		 * how things could possibly work anyways.
+		 */
+		if (cmd->device->device_busy == 0) {
+			if (scsi_retry_command(cmd) == 0) {
+				return 0;
+			}
+		}
+		cmd->device->device_busy = TRUE;
+		cmd->device_wait = TRUE;
+	}
+
+	/*
+	 * Register the fact that we own the thing for now.
+	 */
+	cmd->state = SCSI_STATE_MLQUEUE;
+	cmd->owner = SCSI_OWNER_MIDLEVEL;
+	cmd->bh_next = NULL;
+
+	/*
+	 * As a performance enhancement, look to see whether the list is
+	 * empty.  If it is, then we can just atomicly insert the command
+	 * in the list and return without locking.
+	 */
+	if (host->pending_commands == NULL) {
+		cpnt = xchg(&host->pending_commands, cmd);
+		if (cpnt == NULL) {
+			return 0;
+		}
+		/*
+		 * Rats.  Something slipped in while we were exchanging.
+		 * Swap it back and fall through to do it the hard way.
+		 */
+		cmd = xchg(&host->pending_commands, cpnt);
+
+	}
+	/*
+	 * Next append the command to the list of pending commands.
+	 */
+	spin_lock_irqsave(&scsi_mlqueue_lock, flags);
+	for (cpnt = host->pending_commands; cpnt && cpnt->bh_next;
+	     cpnt = cpnt->bh_next) {
+		continue;
 	}
-
-	host->host_blocked   = TRUE;
-	cmd->host_wait       = TRUE;
-    }
-    else
-    {
-	/*
-	 * Protect against race conditions.  If the device isn't busy,
-	 * assume that something actually completed, and that we should
-	 * be able to queue a command now.  Note that there is an implicit
-	 * assumption that every host can always queue at least one command.
-	 * If a host is inactive and cannot queue any commands, I don't see
-	 * how things could possibly work anyways.
-	 */
-	if( cmd->device->device_busy == 0 )
-	{
-	    if( scsi_retry_command(cmd) == 0 )
-	    {
-		return 0;
-	    }
+	if (cpnt != NULL) {
+		cpnt->bh_next = cmd;
+	} else {
+		host->pending_commands = cmd;
 	}
 
-	cmd->device->device_busy = TRUE;
-	cmd->device_wait         = TRUE;
-    }
-
-    /*
-     * Register the fact that we own the thing for now.
-     */
-    cmd->state = SCSI_STATE_MLQUEUE;
-    cmd->owner = SCSI_OWNER_MIDLEVEL;
-    cmd->bh_next = NULL;
-
-    /*
-     * As a performance enhancement, look to see whether the list is
-     * empty.  If it is, then we can just atomicly insert the command
-     * in the list and return without locking.
-     */
-    if( host->pending_commands == NULL )
-    {
-	cpnt = xchg(&host->pending_commands, cmd);
-	if( cpnt == NULL )
-	{
-	    return 0;
-	}
-	/*
-	 * Rats.  Something slipped in while we were exchanging.
-	 * Swap it back and fall through to do it the hard way.
-	 */
-	cmd = xchg(&host->pending_commands, cpnt);
-
-    }
-
-    /*
-     * Next append the command to the list of pending commands.
-     */
-    spin_lock_irqsave(&scsi_mlqueue_lock, flags);
-    for(cpnt = host->pending_commands; cpnt && cpnt->bh_next; 
-	cpnt = cpnt->bh_next)
-    {
-	continue;
-    }
-    if( cpnt != NULL )
-    {
-	cpnt->bh_next = cmd;
-    }
-    else
-    {
-	host->pending_commands = cmd;
-    }
-
-    spin_unlock_irqrestore(&scsi_mlqueue_lock, flags);
-    return 0;
+	spin_unlock_irqrestore(&scsi_mlqueue_lock, flags);
+	return 0;
 }
 
 /*
@@ -199,118 +183,102 @@
  * Purpose:     Try and queue commands from the midlevel queue.
  *
  * Arguments:   host    - host that just finished a command.
- *		device  - device that just finished a command.
+ *              device  - device that just finished a command.
  *
  * Returns:     Nothing.
  *
- * Notes:	This could be called either from an interrupt context or a
- *		normal process context.
+ * Notes:       This could be called either from an interrupt context or a
+ *              normal process context.
  */
-int
-scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device)
+int scsi_mlqueue_finish(struct Scsi_Host *host, Scsi_Device * device)
 {
-    Scsi_Cmnd      * cpnt;
-    unsigned long    flags;
-    Scsi_Cmnd      * next;
-    Scsi_Cmnd      * prev;
-    int              reason = 0;
-    int              rtn;
-
-    SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish starting\n"));
-    /*
-     * First, clear the flag for the host/device.  We will then start
-     * pushing commands through until either something else blocks, or
-     * the queue is empty.
-     */
-    if( host->host_blocked )
-    {
-	reason = SCSI_MLQUEUE_HOST_BUSY;
-	host->host_blocked = FALSE;
-    }
-
-    if( device->device_busy )
-    {
-	reason = SCSI_MLQUEUE_DEVICE_BUSY;
-	device->device_busy = FALSE;
-    }
-
-    /*
-     * Walk the list of commands to see if there is anything we can
-     * queue.  This probably needs to be optimized for performance at
-     * some point.
-     */
-    prev = NULL;
-    spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags);
-    for(cpnt = host->pending_commands; cpnt; cpnt = next)
-    {
-	next = cpnt->bh_next;
-	/*
-	 * First, see if this command is suitable for being retried now.
-	 */
-	if( reason == SCSI_MLQUEUE_HOST_BUSY )
-	{
-	    /*
-	     * The host was busy, but isn't any more.  Thus we may be
-	     * able to queue the command now, but we were waiting for
-	     * the device, then we should keep waiting.  Similarily, if
-	     * the device is now busy, we should also keep waiting.
-	     */
-	    if(    (cpnt->host_wait == FALSE)
-		|| (device->device_busy == TRUE) )
-	    {
-		prev = cpnt;
-		continue;
-	    }
-	}
-
-	if( reason == SCSI_MLQUEUE_DEVICE_BUSY )
-	{
-	    /*
-	     * The device was busy, but isn't any more.  Thus we may be
-	     * able to queue the command now, but we were waiting for
-	     * the host, then we should keep waiting.  Similarily, if
-	     * the host is now busy, we should also keep waiting.
-	     */
-	    if(    (cpnt->device_wait == FALSE)
-		|| (host->host_blocked == TRUE) )
-	    {
-		prev = cpnt;
-		continue;
-	    }
-	}
-
-	/*
-	 * First, remove the command from the list.
-	 */
-	if( prev == NULL )
-	{
-	    host->pending_commands = next;
-	}
-	else
-	{
-	    prev->bh_next = next;
-	}
-	cpnt->bh_next = NULL;
-
-	rtn = scsi_retry_command(cpnt);
-
-	/*
-	 * If we got a non-zero return value, it means that the host rejected
-	 * the command.  The internal_cmnd function will have added the
-	 * command back to the end of the list, so we don't have anything
-	 * more to do here except return.
-	 */
-	if( rtn )
-	{
-	    spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
-	    SCSI_LOG_MLQUEUE(1,printk("Unable to remove command %p from mlqueue\n", cpnt));
-	    goto finish;
+	Scsi_Cmnd *cpnt;
+	unsigned long flags;
+	Scsi_Cmnd *next;
+	Scsi_Cmnd *prev;
+	int reason = 0;
+	int rtn;
+
+	SCSI_LOG_MLQUEUE(2, printk("scsi_mlqueue_finish starting\n"));
+	/*
+	 * First, clear the flag for the host/device.  We will then start
+	 * pushing commands through until either something else blocks, or
+	 * the queue is empty.
+	 */
+	if (host->host_blocked) {
+		reason = SCSI_MLQUEUE_HOST_BUSY;
+		host->host_blocked = FALSE;
+	}
+	if (device->device_busy) {
+		reason = SCSI_MLQUEUE_DEVICE_BUSY;
+		device->device_busy = FALSE;
+	}
+	/*
+	 * Walk the list of commands to see if there is anything we can
+	 * queue.  This probably needs to be optimized for performance at
+	 * some point.
+	 */
+	prev = NULL;
+	spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags);
+	for (cpnt = host->pending_commands; cpnt; cpnt = next) {
+		next = cpnt->bh_next;
+		/*
+		 * First, see if this command is suitable for being retried now.
+		 */
+		if (reason == SCSI_MLQUEUE_HOST_BUSY) {
+			/*
+			 * The host was busy, but isn't any more.  Thus we may be
+			 * able to queue the command now, but we were waiting for
+			 * the device, then we should keep waiting.  Similarily, if
+			 * the device is now busy, we should also keep waiting.
+			 */
+			if ((cpnt->host_wait == FALSE)
+			    || (device->device_busy == TRUE)) {
+				prev = cpnt;
+				continue;
+			}
+		}
+		if (reason == SCSI_MLQUEUE_DEVICE_BUSY) {
+			/*
+			 * The device was busy, but isn't any more.  Thus we may be
+			 * able to queue the command now, but we were waiting for
+			 * the host, then we should keep waiting.  Similarily, if
+			 * the host is now busy, we should also keep waiting.
+			 */
+			if ((cpnt->device_wait == FALSE)
+			    || (host->host_blocked == TRUE)) {
+				prev = cpnt;
+				continue;
+			}
+		}
+		/*
+		 * First, remove the command from the list.
+		 */
+		if (prev == NULL) {
+			host->pending_commands = next;
+		} else {
+			prev->bh_next = next;
+		}
+		cpnt->bh_next = NULL;
+
+		rtn = scsi_retry_command(cpnt);
+
+		/*
+		 * If we got a non-zero return value, it means that the host rejected
+		 * the command.  The internal_cmnd function will have added the
+		 * command back to the end of the list, so we don't have anything
+		 * more to do here except return.
+		 */
+		if (rtn) {
+			spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
+			SCSI_LOG_MLQUEUE(1, printk("Unable to remove command %p from mlqueue\n", cpnt));
+			goto finish;
+		}
+		SCSI_LOG_MLQUEUE(1, printk("Removed command %p from mlqueue\n", cpnt));
 	}
-	SCSI_LOG_MLQUEUE(1,printk("Removed command %p from mlqueue\n", cpnt));
-    }
 
-    spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
+	spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
 finish:
-    SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish returning\n"));
-    return 0;
+	SCSI_LOG_MLQUEUE(2, printk("scsi_mlqueue_finish returning\n"));
+	return 0;
 }
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c
--- v2.3.16/linux/drivers/scsi/scsicam.c	Wed Jun  9 16:59:16 1999
+++ linux/drivers/scsi/scsicam.c	Sat Sep  4 10:48:46 1999
@@ -5,7 +5,7 @@
  *      Visionary Computing 
  *      (Unix and Linux consulting and custom programming)
  *      drew@Colorado.EDU
- *	+1 (303) 786-7975
+ *      +1 (303) 786-7975
  *
  * For more information, please consult the SCSI-CAM draft.
  */
@@ -23,59 +23,58 @@
 #include "sd.h"
 #include <scsi/scsicam.h>
 
-static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
-    unsigned int *secs);
+static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
+		   unsigned int *secs);
 
 /*
  * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip)
  *
  * Purpose : to determine the BIOS mapping used for a drive in a 
- *	SCSI-CAM system, storing the results in ip as required
- *	by the HDIO_GETGEO ioctl().
+ *      SCSI-CAM system, storing the results in ip as required
+ *      by the HDIO_GETGEO ioctl().
  *
  * Returns : -1 on failure, 0 on success.
  *
  */
 
-int scsicam_bios_param (Disk *disk, /* SCSI disk */
-	kdev_t dev,		/* Device major, minor */
-    	int *ip			/* Heads, sectors, cylinders in that order */) {
-
-    struct buffer_head *bh;
-    int ret_code;
-    int size = disk->capacity;
-    unsigned long temp_cyl;
-
-    if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024)))
-	return -1;
-
-    /* try to infer mapping from partition table */
-    ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2, 
-	(unsigned int *) ip + 0, (unsigned int *) ip + 1);
-    brelse (bh);
-
-    if (ret_code == -1) {
-	/* pick some standard mapping with at most 1024 cylinders,
-	   and at most 62 sectors per track - this works up to
-	   7905 MB */
-	ret_code = setsize ((unsigned long) size, (unsigned int *) ip + 2, 
-    	    (unsigned int *) ip + 0, (unsigned int *) ip + 1);
-    }
-
-    /* if something went wrong, then apparently we have to return
-       a geometry with more than 1024 cylinders */
-    if (ret_code || ip[0] > 255 || ip[1] > 63) {
-	 ip[0] = 64;
-	 ip[1] = 32;
-	 temp_cyl = size / (ip[0] * ip[1]);
-	 if (temp_cyl > 65534) {
-	      ip[0] = 255;
-	      ip[1] = 63;
-	 }
-	 ip[2] = size / (ip[0] * ip[1]);
-    }
-
-    return 0;
+int scsicam_bios_param(Disk * disk,	/* SCSI disk */
+		       kdev_t dev,	/* Device major, minor */
+		  int *ip /* Heads, sectors, cylinders in that order */ )
+{
+
+	struct buffer_head *bh;
+	int ret_code;
+	int size = disk->capacity;
+	unsigned long temp_cyl;
+
+	if (!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024)))
+		return -1;
+
+	/* try to infer mapping from partition table */
+	ret_code = scsi_partsize(bh, (unsigned long) size, (unsigned int *) ip + 2,
+		       (unsigned int *) ip + 0, (unsigned int *) ip + 1);
+	brelse(bh);
+
+	if (ret_code == -1) {
+		/* pick some standard mapping with at most 1024 cylinders,
+		   and at most 62 sectors per track - this works up to
+		   7905 MB */
+		ret_code = setsize((unsigned long) size, (unsigned int *) ip + 2,
+		       (unsigned int *) ip + 0, (unsigned int *) ip + 1);
+	}
+	/* if something went wrong, then apparently we have to return
+	   a geometry with more than 1024 cylinders */
+	if (ret_code || ip[0] > 255 || ip[1] > 63) {
+		ip[0] = 64;
+		ip[1] = 32;
+		temp_cyl = size / (ip[0] * ip[1]);
+		if (temp_cyl > 65534) {
+			ip[0] = 255;
+			ip[1] = 63;
+		}
+		ip[2] = size / (ip[0] * ip[1]);
+	}
+	return 0;
 }
 
 /*
@@ -83,90 +82,90 @@
  *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine the BIOS mapping used to create the partition
- *	table, storing the results in *cyls, *hds, and *secs 
+ *      table, storing the results in *cyls, *hds, and *secs 
  *
  * Returns : -1 on failure, 0 on success.
  *
  */
 
 int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
-    unsigned int  *cyls, unsigned int *hds, unsigned int *secs) {
-    struct partition *p, *largest = NULL;
-    int i, largest_cyl;
-    int cyl, ext_cyl, end_head, end_cyl, end_sector;
-    unsigned int logical_end, physical_end, ext_physical_end;
-    
-
-    if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
-	for (largest_cyl = -1, p = (struct partition *) 
-    	    (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
-    	    if (!p->sys_ind)
-    	    	continue;
+	       unsigned int *cyls, unsigned int *hds, unsigned int *secs)
+{
+	struct partition *p, *largest = NULL;
+	int i, largest_cyl;
+	int cyl, ext_cyl, end_head, end_cyl, end_sector;
+	unsigned int logical_end, physical_end, ext_physical_end;
+
+
+	if (*(unsigned short *) (bh->b_data + 510) == 0xAA55) {
+		for (largest_cyl = -1, p = (struct partition *)
+		     (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) {
+			if (!p->sys_ind)
+				continue;
 #ifdef DEBUG
-	printk ("scsicam_bios_param : partition %d has system \n",
-	    i);
+			printk("scsicam_bios_param : partition %d has system \n",
+			       i);
 #endif
-    	    cyl = p->cyl + ((p->sector & 0xc0) << 2);
-    	    if (cyl > largest_cyl) {
-    	    	largest_cyl = cyl;
-    	    	largest = p;
-    	    }
-    	}
-    }
-
-    if (largest) {
-    	end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
-    	end_head = largest->end_head;
-    	end_sector = largest->end_sector & 0x3f;
+			cyl = p->cyl + ((p->sector & 0xc0) << 2);
+			if (cyl > largest_cyl) {
+				largest_cyl = cyl;
+				largest = p;
+			}
+		}
+	}
+	if (largest) {
+		end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
+		end_head = largest->end_head;
+		end_sector = largest->end_sector & 0x3f;
 
-        if( end_head + 1 == 0 || end_sector == 0 ) return -1;
+		if (end_head + 1 == 0 || end_sector == 0)
+			return -1;
 
 #ifdef DEBUG
-	printk ("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
-	    end_head, end_cyl, end_sector);
+		printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
+		       end_head, end_cyl, end_sector);
 #endif
 
-    	physical_end =  end_cyl * (end_head + 1) * end_sector +
-    	    end_head * end_sector + end_sector;
+		physical_end = end_cyl * (end_head + 1) * end_sector +
+		    end_head * end_sector + end_sector;
 
-	/* This is the actual _sector_ number at the end */
-	logical_end = get_unaligned(&largest->start_sect)
-			+ get_unaligned(&largest->nr_sects);
-
-	/* This is for >1023 cylinders */
-        ext_cyl= (logical_end-(end_head * end_sector + end_sector))
-                                        /(end_head + 1) / end_sector;
-	ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
-            end_head * end_sector + end_sector;
+		/* This is the actual _sector_ number at the end */
+		logical_end = get_unaligned(&largest->start_sect)
+		    + get_unaligned(&largest->nr_sects);
+
+		/* This is for >1023 cylinders */
+		ext_cyl = (logical_end - (end_head * end_sector + end_sector))
+		    / (end_head + 1) / end_sector;
+		ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
+		    end_head * end_sector + end_sector;
 
 #ifdef DEBUG
-	printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n"
-			,logical_end,physical_end,ext_physical_end,ext_cyl);
+		printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n"
+		  ,logical_end, physical_end, ext_physical_end, ext_cyl);
 #endif
 
-    	if ((logical_end == physical_end) ||
-	    (end_cyl==1023 && ext_physical_end==logical_end)) {
-    	    *secs = end_sector;
-    	    *hds = end_head + 1;
-    	    *cyls = capacity / ((end_head + 1) * end_sector);
-    	    return 0;
-    	}
-	
+		if ((logical_end == physical_end) ||
+		  (end_cyl == 1023 && ext_physical_end == logical_end)) {
+			*secs = end_sector;
+			*hds = end_head + 1;
+			*cyls = capacity / ((end_head + 1) * end_sector);
+			return 0;
+		}
 #ifdef DEBUG
-	printk ("scsicam_bios_param : logical (%u) != physical (%u)\n",
-	    logical_end, physical_end);
+		printk("scsicam_bios_param : logical (%u) != physical (%u)\n",
+		       logical_end, physical_end);
 #endif
-    }
-    return -1;
+	}
+	return -1;
 }
 
 /*
  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
- *	unsigned int *hds, unsigned int *secs);
+ *      unsigned int *hds, unsigned int *secs);
  *
  * Purpose : to determine a near-optimal int 0x13 mapping for a
- *	SCSI disk in terms of lost space of size capacity, storing
- *	the results in *cyls, *hds, and *secs.
+ *      SCSI disk in terms of lost space of size capacity, storing
+ *      the results in *cyls, *hds, and *secs.
  *
  * Returns : -1 on failure, 0 on success.
  *
@@ -194,31 +193,33 @@
  * accommodated. This algorithm does not use physical geometry. 
  */
 
-static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
-    unsigned int *secs) { 
-    unsigned int rv = 0; 
-    unsigned long heads, sectors, cylinders, temp; 
-
-    cylinders = 1024L;			/* Set number of cylinders to max */ 
-    sectors = 62L;      		/* Maximize sectors per track */ 
-
-    temp = cylinders * sectors;		/* Compute divisor for heads */ 
-    heads = capacity / temp;		/* Compute value for number of heads */
-    if (capacity % temp) {		/* If no remainder, done! */ 
-    	heads++;                	/* Else, increment number of heads */ 
-    	temp = cylinders * heads;	/* Compute divisor for sectors */ 
-    	sectors = capacity / temp;	/* Compute value for sectors per
-					       track */ 
-    	if (capacity % temp) {		/* If no remainder, done! */ 
-      	    sectors++;                  /* Else, increment number of sectors */ 
-      	    temp = heads * sectors;	/* Compute divisor for cylinders */
-      	    cylinders = capacity / temp;/* Compute number of cylinders */ 
-      	} 
-    } 
-    if (cylinders == 0) rv=(unsigned)-1;/* Give error if 0 cylinders */ 
-
-    *cyls = (unsigned int) cylinders;	/* Stuff return values */ 
-    *secs = (unsigned int) sectors; 
-    *hds  = (unsigned int) heads; 
-    return(rv); 
-} 
+static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
+		   unsigned int *secs)
+{
+	unsigned int rv = 0;
+	unsigned long heads, sectors, cylinders, temp;
+
+	cylinders = 1024L;	/* Set number of cylinders to max */
+	sectors = 62L;		/* Maximize sectors per track */
+
+	temp = cylinders * sectors;	/* Compute divisor for heads */
+	heads = capacity / temp;	/* Compute value for number of heads */
+	if (capacity % temp) {	/* If no remainder, done! */
+		heads++;	/* Else, increment number of heads */
+		temp = cylinders * heads;	/* Compute divisor for sectors */
+		sectors = capacity / temp;	/* Compute value for sectors per
+						   track */
+		if (capacity % temp) {	/* If no remainder, done! */
+			sectors++;	/* Else, increment number of sectors */
+			temp = heads * sectors;		/* Compute divisor for cylinders */
+			cylinders = capacity / temp;	/* Compute number of cylinders */
+		}
+	}
+	if (cylinders == 0)
+		rv = (unsigned) -1;	/* Give error if 0 cylinders */
+
+	*cyls = (unsigned int) cylinders;	/* Stuff return values */
+	*secs = (unsigned int) sectors;
+	*hds = (unsigned int) heads;
+	return (rv);
+}
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c
--- v2.3.16/linux/drivers/scsi/scsiiom.c	Fri Dec 25 16:41:39 1998
+++ linux/drivers/scsi/scsiiom.c	Sat Sep  4 10:48:46 1999
@@ -7,165 +7,156 @@
 /* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */
 
 UCHAR
-dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
+dc390_StartSCSI(PACB pACB, PDCB pDCB, PSRB pSRB)
 {
-    USHORT wlval;
-    UCHAR  bval, bval1;
+	USHORT wlval;
+	UCHAR bval, bval1;
 
-    pSRB->TagNumber = 31;
-    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
-    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
-    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
-    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
-    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
-    DC390_write8 (CtrlReg4, pDCB->CtrlR4);
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);		/* Flush FIFO */
-    DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
-	    pSRB->CmdBlock[0], pDCB->SyncMode);)
-    pSRB->ScsiPhase = SCSI_NOP0;
-    //pSRB->MsgOutBuf[0] = MSG_NOP;
-    //pSRB->MsgCnt = 0;
-    bval = pDCB->IdentifyMsg;
-    if( !(pDCB->SyncMode & EN_ATN_STOP) )	/* Don't always try send Extended messages on arbitration */
-    {
-	if( (pSRB->CmdBlock[0] == INQUIRY) ||
-	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
-	    (pSRB->SRBFlag & AUTO_REQSENSE) )
-	{
-	    bval &= 0xBF;	/* No DisConn */
-	    DC390_write8 (ScsiFifo, bval);
-	    bval1 = SEL_W_ATN;
-	    pSRB->SRBState = SRB_START_;
-	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
-	    if( pDCB->SyncMode & SYNC_ENABLE )
-		{
-		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
-		    (pSRB->CmdBlock[0] != INQUIRY) )
-		{
-		    bval1 = SEL_W_ATN_STOP;	/* Try to establish SYNC nego */
-		    pSRB->SRBState = SRB_MSGOUT;
+	pSRB->TagNumber = 31;
+	DC390_write8(Scsi_Dest_ID, pDCB->UnitSCSIID);
+	DC390_write8(Sync_Period, pDCB->SyncPeriod);
+	DC390_write8(Sync_Offset, pDCB->SyncOffset);
+	DC390_write8(CtrlReg1, pDCB->CtrlR1);
+	DC390_write8(CtrlReg3, pDCB->CtrlR3);
+	DC390_write8(CtrlReg4, pDCB->CtrlR4);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);	/* Flush FIFO */
+	DEBUG1(printk(KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n", \
+		      pSRB->CmdBlock[0], pDCB->SyncMode);
+	    )
+	    pSRB->ScsiPhase = SCSI_NOP0;
+	//pSRB->MsgOutBuf[0] = MSG_NOP;
+	//pSRB->MsgCnt = 0;
+	bval = pDCB->IdentifyMsg;
+	if (!(pDCB->SyncMode & EN_ATN_STOP)) {	/* Don't always try send Extended messages on arbitration */
+		if ((pSRB->CmdBlock[0] == INQUIRY) ||
+		    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+		    (pSRB->SRBFlag & AUTO_REQSENSE)) {
+			bval &= 0xBF;	/* No DisConn */
+			DC390_write8(ScsiFifo, bval);
+			bval1 = SEL_W_ATN;
+			pSRB->SRBState = SRB_START_;
+			DEBUG1(printk(KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);
+			    )
+			    if (pDCB->SyncMode & SYNC_ENABLE) {
+				if (!(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
+				    (pSRB->CmdBlock[0] != INQUIRY)) {
+					bval1 = SEL_W_ATN_STOP;		/* Try to establish SYNC nego */
+					pSRB->SRBState = SRB_MSGOUT;
+				}
+			}
+		} else {	/* TagQ ? */
+			DC390_write8(ScsiFifo, bval);
+			if (pDCB->SyncMode & EN_TAG_QUEUEING) {
+				DC390_write8(ScsiFifo, MSG_SIMPLE_QTAG);
+				DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, SEL_W_ATN3, pDCB->TagMask);
+				    )
+				    bval = 0;
+				wlval = 1;
+				while (wlval & pDCB->TagMask) {
+					bval++;
+					wlval <<= 1;
+				};
+				pDCB->TagMask |= wlval;
+				DC390_write8(ScsiFifo, bval);
+				pSRB->TagNumber = bval;
+				DEBUG1(printk(KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);
+				    )
+				    bval1 = SEL_W_ATN3;
+				pSRB->SRBState = SRB_START_;
+			} else {	/* No TagQ */
+				bval1 = SEL_W_ATN;
+				DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, bval1, pDCB->TagMask);
+				    )
+				    pSRB->SRBState = SRB_START_;
+			}
 		}
-	    }
-	}
-	else	/* TagQ ? */
-	{
-	    DC390_write8 (ScsiFifo, bval);
-	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
-	    {
-	        DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
-	        bval = 0; wlval = 1;
-	        while (wlval & pDCB->TagMask)
-		  { bval++; wlval <<= 1; };
-		pDCB->TagMask |= wlval;
-	        DC390_write8 (ScsiFifo, bval);
-		pSRB->TagNumber = bval;
-		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
-		bval1 = SEL_W_ATN3;
-		pSRB->SRBState = SRB_START_;
-	    }
-	    else	/* No TagQ */
-	    {
-		bval1 = SEL_W_ATN;
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
-		pSRB->SRBState = SRB_START_;
-	    }
-	}
-
-    }
-    else	/* ATN_STOP: Always try to establish Sync nego */
-    {
-	if( (pSRB->CmdBlock[0] == INQUIRY) ||
-	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
-	    (pSRB->SRBFlag & AUTO_REQSENSE) )
-	{
-	    bval &= 0xBF;	/* No DisConn */
-	    DC390_write8 (ScsiFifo, bval);
-	    bval1 = SEL_W_ATN;
-	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
-	    pSRB->SRBState = SRB_START_;
-	      /* ??? */
-	    if( pDCB->SyncMode & SYNC_ENABLE )
-	    {
-		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
-		    (pSRB->CmdBlock[0] != INQUIRY) )
-		{
-		    bval1 = SEL_W_ATN_STOP;	/* Try to establish Sync nego */
-		    pSRB->SRBState = SRB_MSGOUT;
+
+	} else {		/* ATN_STOP: Always try to establish Sync nego */
+		if ((pSRB->CmdBlock[0] == INQUIRY) ||
+		    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+		    (pSRB->SRBFlag & AUTO_REQSENSE)) {
+			bval &= 0xBF;	/* No DisConn */
+			DC390_write8(ScsiFifo, bval);
+			bval1 = SEL_W_ATN;
+			DEBUG1(printk(KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);
+			    )
+			    pSRB->SRBState = SRB_START_;
+			/* ??? */
+			if (pDCB->SyncMode & SYNC_ENABLE) {
+				if (!(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
+				    (pSRB->CmdBlock[0] != INQUIRY)) {
+					bval1 = SEL_W_ATN_STOP;		/* Try to establish Sync nego */
+					pSRB->SRBState = SRB_MSGOUT;
+				}
+			}
+		} else {	/* TagQ ? */
+			DC390_write8(ScsiFifo, bval);
+			if (pDCB->SyncMode & EN_TAG_QUEUEING) {
+				pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
+				DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);
+				    )
+				    bval = 0;
+				wlval = 1;
+				while (wlval & pDCB->TagMask) {
+					bval++;
+					wlval <<= 1;
+				};
+				pDCB->TagMask |= wlval;
+				pSRB->TagNumber = bval;
+				DEBUG1(printk(KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);
+				    )
+				    pSRB->MsgOutBuf[1] = bval;
+				pSRB->MsgCnt = 2;
+				bval1 = SEL_W_ATN_STOP;
+				pSRB->SRBState = SRB_START_;	/* ?? */
+			} else {	/* No TagQ */
+				pSRB->MsgOutBuf[0] = MSG_NOP;
+				pSRB->MsgCnt = 1;
+				pSRB->SRBState = SRB_START_;
+				bval1 = SEL_W_ATN_STOP;
+				DEBUG1(printk(KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval & 0x40 ? "" : "No "), bval, bval1, pDCB->TagMask);
+				    )
+			};
 		}
-	    }
 	}
-	else	/* TagQ ? */
-	{
-	    DC390_write8 (ScsiFifo, bval);
-	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
-	    {
-		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
-		bval = 0; wlval = 1;
-	        while (wlval & pDCB->TagMask)
-		  { bval++; wlval <<= 1; };
-		pDCB->TagMask |= wlval;
-		pSRB->TagNumber = bval;
-		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
-		pSRB->MsgOutBuf[1] = bval;
-		pSRB->MsgCnt = 2;
-		bval1 = SEL_W_ATN_STOP;
-		pSRB->SRBState = SRB_START_;	/* ?? */
-	    }
-	    else	/* No TagQ */
-	    {
-		pSRB->MsgOutBuf[0] = MSG_NOP;
-		pSRB->MsgCnt = 1;
-		pSRB->SRBState = SRB_START_;
-		bval1 = SEL_W_ATN_STOP;
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
-	    };
-	}
-    }
-    if (bval1 != SEL_W_ATN_STOP)
-      {	/* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
-	if( pSRB->SRBFlag & AUTO_REQSENSE )
-	  {
-	    bval = 0;
-	    DC390_write8 (ScsiFifo, REQUEST_SENSE);
-	    DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
-	    DC390_write8 (ScsiFifo, bval);
-	    DC390_write8 (ScsiFifo, bval);
-	    DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
-	    DC390_write8 (ScsiFifo, bval);
-	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");)
-	  }
-	else	/* write cmnd to bus */ 
-	  {
-	    PUCHAR ptr; UCHAR i;
-	    ptr = (PUCHAR) pSRB->CmdBlock;
-	    for (i=0; i<pSRB->ScsiCmdLen; i++)
-	      DC390_write8 (ScsiFifo, *(ptr++));
-	  };
-      }
-
-    /* Check if we can't win arbitration */
-    if (DC390_read8 (Scsi_Status) & INTERRUPT)
-    {
-	pSRB->SRBState = SRB_READY;
-	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
-	DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");)
-	return 1;
-    }
-    else
-    {
-	pSRB->ScsiPhase = SCSI_NOP1;
-	DEBUG0(if (pACB->pActiveDCB)	\
-		    printk (KERN_WARNING "DC390: ActiveDCB != 0\n");)
-	DEBUG0(if (pDCB->pActiveSRB)	\
-		    printk (KERN_WARNING "DC390: ActiveSRB != 0\n");)
-	pACB->pActiveDCB = pDCB;
-	pDCB->pActiveSRB = pSRB;
-	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-	DC390_write8 (ScsiCmd, bval1);
-	return 0;
-    }
+	if (bval1 != SEL_W_ATN_STOP) {	/* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+		if (pSRB->SRBFlag & AUTO_REQSENSE) {
+			bval = 0;
+			DC390_write8(ScsiFifo, REQUEST_SENSE);
+			DC390_write8(ScsiFifo, pDCB->IdentifyMsg << 5);
+			DC390_write8(ScsiFifo, bval);
+			DC390_write8(ScsiFifo, bval);
+			DC390_write8(ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+			DC390_write8(ScsiFifo, bval);
+			DEBUG1(printk(KERN_DEBUG "DC390: AutoReqSense !\n");
+			    )
+		} else {	/* write cmnd to bus */
+			PUCHAR ptr;
+			UCHAR i;
+			ptr = (PUCHAR) pSRB->CmdBlock;
+			for (i = 0; i < pSRB->ScsiCmdLen; i++)
+				DC390_write8(ScsiFifo, *(ptr++));
+		};
+	}
+	/* Check if we can't win arbitration */
+	if (DC390_read8(Scsi_Status) & INTERRUPT) {
+		pSRB->SRBState = SRB_READY;
+		pDCB->TagMask &= ~(1 << pSRB->TagNumber);
+		DEBUG0(printk(KERN_WARNING "DC390: Interrupt during StartSCSI!\n");
+		    )
+		    return 1;
+	} else {
+		pSRB->ScsiPhase = SCSI_NOP1;
+		DEBUG0(if (pACB->pActiveDCB) \
+		       printk(KERN_WARNING "DC390: ActiveDCB != 0\n");)
+			DEBUG0(if (pDCB->pActiveSRB) \
+			 printk(KERN_WARNING "DC390: ActiveSRB != 0\n");)
+				pACB->pActiveDCB = pDCB;
+		pDCB->pActiveSRB = pSRB;
+		//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+		DC390_write8(ScsiCmd, bval1);
+		return 0;
+	}
 }
 
 //#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
@@ -173,417 +164,400 @@
 
 #if DMA_INT
 /* This is similar to AM53C974.c ... */
-static UCHAR 
-dc390_dma_intr (PACB pACB)
+static UCHAR
+ dc390_dma_intr(PACB pACB)
 {
-  PSRB pSRB;
-  UCHAR dstate;
-  DEBUG0(USHORT pstate;PDEVDECL1;)
-  
-  DEBUG0(PDEVSET1;)
-  DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);)
-  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
-	{ printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
-	  PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};)
-
-  dstate = DC390_read8 (DMA_Status); 
-
-  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
-  else pSRB  = pACB->pActiveDCB->pActiveSRB;
-  
-  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
-    {
-	printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
-	return dstate;
-    };
-  if (dstate & DMA_XFER_DONE)
-    {
-	ULONG residual, xferCnt; int ctr = 5000000;
-	if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
-	  {
-	    do
-	      {
-		DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");)
-		dstate = DC390_read8 (DMA_Status);
-		residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
-		  DC390_read8 (CtcReg_High) << 16;
-		residual += DC390_read8 (Current_Fifo) & 0x1f;
-	      } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
-	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-	    /* residual =  ... */
-	  }
+	PSRB pSRB;
+	UCHAR dstate;
+	DEBUG0(USHORT pstate;
+	       PDEVDECL1;
+	    )
+	    DEBUG0(PDEVSET1;
+	    )
+	    DEBUG0(PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstate);
+	    )
+	    DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)) \
+		   {
+		   printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
+		   PCI_WRITE_CONFIG_WORD(PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));
+		   };
+	    )
+		dstate = DC390_read8(DMA_Status);
+
+	if (!pACB->pActiveDCB || !pACB->pActiveDCB->pActiveSRB)
+		return dstate;
 	else
-	    residual = 0;
-	
-	/* ??? */
-	
-	xferCnt = pSRB->SGToBeXferLen - residual;
-	pSRB->SGBusAddr += xferCnt;
-	pSRB->TotalXferredLen += xferCnt;
-	pSRB->SGToBeXferLen = residual;
-# ifdef DC390_DEBUG0
-	printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
-		(unsigned int)residual, (unsigned int)xferCnt);
-# endif
-	
-	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-    }
-  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
-  return dstate;
+		pSRB = pACB->pActiveDCB->pActiveSRB;
+
+	if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) {
+		printk(KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
+		return dstate;
+	};
+	if (dstate & DMA_XFER_DONE) {
+		ULONG residual, xferCnt;
+		int ctr = 5000000;
+		if (!(DC390_read8(DMA_Cmd) & READ_DIRECTION)) {
+			do {
+				DEBUG1(printk(KERN_DEBUG "DC390: read residual bytes ... \n");
+				    )
+				    dstate = DC390_read8(DMA_Status);
+				residual = DC390_read8(CtcReg_Low) | DC390_read8(CtcReg_Mid) << 8 |
+				    DC390_read8(CtcReg_High) << 16;
+				residual += DC390_read8(Current_Fifo) & 0x1f;
+			} while (residual && !(dstate & SCSI_INTERRUPT) && --ctr);
+			if (!ctr)
+				printk(KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr));
+			/* residual =  ... */
+		} else
+			residual = 0;
+
+		/* ??? */
+
+		xferCnt = pSRB->SGToBeXferLen - residual;
+		pSRB->SGBusAddr += xferCnt;
+		pSRB->TotalXferredLen += xferCnt;
+		pSRB->SGToBeXferLen = residual;
+#ifdef DC390_DEBUG0
+		printk(KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n",
+		       (unsigned int) residual, (unsigned int) xferCnt);
+#endif
+
+		DC390_write8(DMA_Cmd, DMA_IDLE_CMD);
+	}
+	dc390_laststatus &= ~0xff000000;
+	dc390_laststatus |= dstate << 24;
+	return dstate;
 };
 #endif
 
 void __inline__
-DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+ DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-    PACB   pACB;
-    PDCB   pDCB;
-    PSRB   pSRB;
-    UCHAR  sstatus=0;
-    UCHAR  phase, i;
-    void   (*stateV)( PACB, PSRB, PUCHAR );
-    UCHAR  istate, istatus;
+	PACB pACB;
+	PDCB pDCB;
+	PSRB pSRB;
+	UCHAR sstatus = 0;
+	UCHAR phase, i;
+	void (*stateV) (PACB, PSRB, PUCHAR);
+	UCHAR istate, istatus;
 #if DMA_INT
-    UCHAR  dstatus;
+	UCHAR dstatus;
 #endif
-    DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
-
-    pACB = dc390_pACB_start;
+	DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
 
-    if (pACB == 0)
-    {
-	printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n");
-	return;
-    }
-    DC390_LOCK_DRV;
+	 pACB = dc390_pACB_start;
 
-    for( i=0; i < dc390_adapterCnt; i++ )
-    {
-	if( pACB->IRQLevel == (UCHAR) irq )
-	{
-	     sstatus = DC390_read8 (Scsi_Status);
-	     if( sstatus & INTERRUPT )
-		 break;
-	     else
-		pACB = pACB->pNextACB;
-	}
-	else
-	{
-	    pACB = pACB->pNextACB;
+	if (pACB == 0) {
+		printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n");
+		return;
 	}
-    }
+	DC390_LOCK_DRV;
 
-    DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
+	for (i = 0; i < dc390_adapterCnt; i++) {
+		if (pACB->IRQLevel == (UCHAR) irq) {
+			sstatus = DC390_read8(Scsi_Status);
+			if (sstatus & INTERRUPT)
+				break;
+			else
+				pACB = pACB->pNextACB;
+		} else {
+			pACB = pACB->pNextACB;
+		}
+	}
 
-    if( !pACB ) { DC390_UNLOCK_DRV; return; };
+	DEBUG1(printk(KERN_DEBUG "sstatus=%02x,", sstatus);
+	    )
+	    if (!pACB) {
+		DC390_UNLOCK_DRV;
+		return;
+	};
 
 #if DMA_INT
-    DC390_LOCK_IO;
-    DC390_LOCK_ACB;
-    dstatus = dc390_dma_intr (pACB);
-    DC390_UNLOCK_ACB;
-    DC390_UNLOCK_IO;
-
-    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus);)
-    if (! (dstatus & SCSI_INTERRUPT))
-      {
-	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");)
-	DC390_UNLOCK_DRV;
-	return;
-      };
+	DC390_LOCK_IO;
+	DC390_LOCK_ACB;
+	dstatus = dc390_dma_intr(pACB);
+	DC390_UNLOCK_ACB;
+	DC390_UNLOCK_IO;
+
+	DEBUG1(printk(KERN_DEBUG "dstatus=%02x,", dstatus);
+	    )
+	    if (!(dstatus & SCSI_INTERRUPT)) {
+		DEBUG0(printk(KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");
+		    )
+		    DC390_UNLOCK_DRV;
+		return;
+	};
 #else
-    //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
-    //dstatus = DC390_read8 (DMA_Status);
-    //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
+	//DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+	//dstatus = DC390_read8 (DMA_Status);
+	//DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
 #endif
 
-    DC390_LOCK_IO;
-    DC390_LOCK_ACB;
-    DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
-
-    istate = DC390_read8 (Intern_State);
-    istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
-
-    DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
-    dc390_laststatus &= ~0x00ffffff;
-    dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus;
-
-    if (sstatus & ILLEGAL_OP_ERR)
-    {
-	printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
-	dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
-    };
-	
-    if(istatus &  DISCONNECTED)
-    {
-	dc390_Disconnect( pACB );
-	goto unlock;
-    }
-
-    if(istatus &  RESELECTED)
-    {
-	dc390_Reselect( pACB );
-	goto unlock;
-    }
-
-    if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
-    {
-	pDCB = pACB->pActiveDCB;
-	if (!pDCB)
-	{
-		printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
-		goto unlock;
+	DC390_LOCK_IO;
+	DC390_LOCK_ACB;
+	DC390_UNLOCK_DRV_NI;	/* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
+
+	istate = DC390_read8(Intern_State);
+	istatus = DC390_read8(INT_Status);	/* This clears Scsi_Status, Intern_State and INT_Status ! */
+
+	DEBUG1(printk(KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,", istatus);
+	    )
+	    dc390_laststatus &= ~0x00ffffff;
+	dc390_laststatus |= /* dstatus<<24 | */ sstatus << 16 | istate << 8 | istatus;
+
+	if (sstatus & ILLEGAL_OP_ERR) {
+		printk("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+		dc390_dumpinfo(pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
 	};
-	pSRB = pDCB->pActiveSRB;
-	if( pDCB->DCBFlag & ABORT_DEV_ )
-	  dc390_EnableMsgOut_Abort (pACB, pSRB);
-
-	phase = pSRB->ScsiPhase;
-	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);)
-	stateV = (void *) dc390_phase0[phase];
-	( *stateV )( pACB, pSRB, &sstatus );
-
-	pSRB->ScsiPhase = sstatus & 7;
-	phase = (UCHAR) sstatus & 7;
-	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);)
-	stateV = (void *) dc390_phase1[phase];
-	( *stateV )( pACB, pSRB, &sstatus );
-	goto unlock;
-    }
-
-    if(istatus &  INVALID_CMD)
-    {
-	dc390_InvalidCmd( pACB );
-	goto unlock;
-    }
-
-    if(istatus &  SCSI_RESET)
-    {
-	dc390_ScsiRstDetect( pACB );
-	goto unlock;
-    }
-
- unlock:
-    DC390_LOCK_DRV_NI;
-    DC390_UNLOCK_ACB;
-    DC390_UNLOCK_IO;
-    DC390_UNLOCK_DRV; /* Restore initial flags */
-}
-
-void
-do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
-{
-    DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);)
-    /* Locking is done in DC390_Interrupt */
-    DC390_Interrupt(irq, dev_id, regs);
-    DEBUG1(printk (".. IRQ returned\n");)
-}
-
-void
-dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
-{
-    UCHAR   sstatus;
-    PSGL    psgl;
-    ULONG   ResidCnt, xferCnt;
-    UCHAR   dstate = 0;
-
-    sstatus = *psstatus;
-
-    if( !(pSRB->SRBState & SRB_XFERPAD) )
-    {
-	if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) )
-	    pSRB->SRBStatus |= PARITY_ERROR;
 
-	if( sstatus & COUNT_2_ZERO )
-	{
-	    int ctr = 5000000; /* only try for about a tenth of a second */
-	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
-	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
-	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
-	    pSRB->SGIndex++;
-	    if( pSRB->SGIndex < pSRB->SGcount )
-	    {
-		pSRB->pSegmentList++;
-		psgl = pSRB->pSegmentList;
-
-		pSRB->SGBusAddr = virt_to_bus( psgl->address );
-		pSRB->SGToBeXferLen = (ULONG) psgl->length;
-	    }
-	    else
-		pSRB->SGToBeXferLen = 0;
+	if (istatus & DISCONNECTED) {
+		dc390_Disconnect(pACB);
+		goto unlock;
 	}
-	else
-	{
-	    ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; 
-	    ResidCnt += (ULONG) DC390_read8 (CtcReg_Low);
+	if (istatus & RESELECTED) {
+		dc390_Reselect(pACB);
+		goto unlock;
+	}
+	if (istatus & (SUCCESSFUL_OP | SERVICE_REQUEST)) {
+		pDCB = pACB->pActiveDCB;
+		if (!pDCB) {
+			printk(KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
+			goto unlock;
+		};
+		pSRB = pDCB->pActiveSRB;
+		if (pDCB->DCBFlag & ABORT_DEV_)
+			dc390_EnableMsgOut_Abort(pACB, pSRB);
+
+		phase = pSRB->ScsiPhase;
+		DEBUG1(printk(KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);
+		    )
+		    stateV = (void *) dc390_phase0[phase];
+		(*stateV) (pACB, pSRB, &sstatus);
+
+		pSRB->ScsiPhase = sstatus & 7;
+		phase = (UCHAR) sstatus & 7;
+		DEBUG1(printk(KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);
+		    )
+		    stateV = (void *) dc390_phase1[phase];
+		(*stateV) (pACB, pSRB, &sstatus);
+		goto unlock;
+	}
+	if (istatus & INVALID_CMD) {
+		dc390_InvalidCmd(pACB);
+		goto unlock;
+	}
+	if (istatus & SCSI_RESET) {
+		dc390_ScsiRstDetect(pACB);
+		goto unlock;
+	}
+      unlock:
+	DC390_LOCK_DRV_NI;
+	DC390_UNLOCK_ACB;
+	DC390_UNLOCK_IO;
+	DC390_UNLOCK_DRV;	/* Restore initial flags */
+}
+
+void do_DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	DEBUG1(printk(KERN_INFO "DC390: Irq (%i) caught: ", irq);
+	    )
+	/* Locking is done in DC390_Interrupt */
+	    DC390_Interrupt(irq, dev_id, regs);
+	DEBUG1(printk(".. IRQ returned\n");
+	    )
+}
+
+void dc390_DataOut_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+	UCHAR sstatus;
+	PSGL psgl;
+	ULONG ResidCnt, xferCnt;
+	UCHAR dstate = 0;
+
+	sstatus = *psstatus;
+
+	if (!(pSRB->SRBState & SRB_XFERPAD)) {
+		if (sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
+			pSRB->SRBStatus |= PARITY_ERROR;
+
+		if (sstatus & COUNT_2_ZERO) {
+			int ctr = 5000000;	/* only try for about a tenth of a second */
+			while (--ctr && !((dstate = DC390_read8(DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen);
+			if (!ctr)
+				printk(KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr));
+			dc390_laststatus &= ~0xff000000;
+			dc390_laststatus |= dstate << 24;
+			pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+			pSRB->SGIndex++;
+			if (pSRB->SGIndex < pSRB->SGcount) {
+				pSRB->pSegmentList++;
+				psgl = pSRB->pSegmentList;
+
+				pSRB->SGBusAddr = virt_to_bus(psgl->address);
+				pSRB->SGToBeXferLen = (ULONG) psgl->length;
+			} else
+				pSRB->SGToBeXferLen = 0;
+		} else {
+			ResidCnt = (ULONG) DC390_read8(Current_Fifo) & 0x1f;
+			ResidCnt |= (ULONG) DC390_read8(CtcReg_High) << 16;
+			ResidCnt |= (ULONG) DC390_read8(CtcReg_Mid) << 8;
+			ResidCnt += (ULONG) DC390_read8(CtcReg_Low);
+
+			xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+			pSRB->SGBusAddr += xferCnt;
+			pSRB->TotalXferredLen += xferCnt;
+			pSRB->SGToBeXferLen = ResidCnt;
+		}
+	}
+	DC390_write8(DMA_Cmd, WRITE_DIRECTION + DMA_IDLE_CMD);	/* | DMA_INT */
+}
 
-	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-	    pSRB->SGBusAddr += xferCnt;
-	    pSRB->TotalXferredLen += xferCnt;
-	    pSRB->SGToBeXferLen = ResidCnt;
+void dc390_DataIn_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+	UCHAR sstatus, residual, bval;
+	PSGL psgl;
+	ULONG ResidCnt, xferCnt, i;
+	PUCHAR ptr;
+
+	sstatus = *psstatus;
+
+	if (!(pSRB->SRBState & SRB_XFERPAD)) {
+		if (sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
+			pSRB->SRBStatus |= PARITY_ERROR;
+
+		if (sstatus & COUNT_2_ZERO) {
+			int ctr = 5000000;	/* only try for about a tenth of a second */
+			int dstate = 0;
+			while (--ctr && !((dstate = DC390_read8(DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen);
+			if (!ctr)
+				printk(KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32(DMA_Wk_ByteCntr));
+			if (!ctr)
+				printk(KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+			dc390_laststatus &= ~0xff000000;
+			dc390_laststatus |= dstate << 24;
+			DEBUG1(ResidCnt = ((ULONG) DC390_read8(CtcReg_High) << 16) \
+			       +((ULONG) DC390_read8(CtcReg_Mid) << 8) \
+			       +((ULONG) DC390_read8(CtcReg_Low));
+			    )
+			    DEBUG1(printk(KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);
+			    )
+			    DC390_write8(DMA_Cmd, READ_DIRECTION + DMA_IDLE_CMD);	/* | DMA_INT */
+
+			pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+			pSRB->SGIndex++;
+			if (pSRB->SGIndex < pSRB->SGcount) {
+				pSRB->pSegmentList++;
+				psgl = pSRB->pSegmentList;
+
+				pSRB->SGBusAddr = virt_to_bus(psgl->address);
+				pSRB->SGToBeXferLen = (ULONG) psgl->length;
+			} else
+				pSRB->SGToBeXferLen = 0;
+		} else {	/* phase changed */
+			residual = 0;
+			bval = DC390_read8(Current_Fifo);
+			while (bval & 0x1f) {
+				DEBUG1(printk(KERN_DEBUG "Check for residuals,");
+				    )
+				    if ((bval & 0x1f) == 1) {
+					for (i = 0; i < 0x100; i++) {
+						bval = DC390_read8(Current_Fifo);
+						if (!(bval & 0x1f))
+							goto din_1;
+						else if (i == 0x0ff) {
+							residual = 1;	/* ;1 residual byte */
+							goto din_1;
+						}
+					}
+				} else
+					bval = DC390_read8(Current_Fifo);
+			}
+		      din_1:
+			DC390_write8(DMA_Cmd, READ_DIRECTION + DMA_BLAST_CMD);
+			for (i = 0xa000; i; i--) {
+				bval = DC390_read8(DMA_Status);
+				if (bval & BLAST_COMPLETE)
+					break;
+			}
+			/* It seems a DMA Blast abort isn't that bad ... */
+			if (!i)
+				printk(KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
+			//DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+			dc390_laststatus &= ~0xff000000;
+			dc390_laststatus |= bval << 24;
+
+			DEBUG1(printk(KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000 - i, bval);
+			    )
+			    ResidCnt = (ULONG) DC390_read8(CtcReg_High);
+			ResidCnt <<= 8;
+			ResidCnt |= (ULONG) DC390_read8(CtcReg_Mid);
+			ResidCnt <<= 8;
+			ResidCnt |= (ULONG) DC390_read8(CtcReg_Low);
+
+			xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+			pSRB->SGBusAddr += xferCnt;
+			pSRB->TotalXferredLen += xferCnt;
+			pSRB->SGToBeXferLen = ResidCnt;
+
+			if (residual) {
+				bval = DC390_read8(ScsiFifo);	/* get one residual byte */
+				ptr = (PUCHAR) bus_to_virt(pSRB->SGBusAddr);
+				*ptr = bval;
+				pSRB->SGBusAddr++;
+				xferCnt++;
+				pSRB->TotalXferredLen++;
+				pSRB->SGToBeXferLen--;
+			}
+			DEBUG1(printk(KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt, \
+			     pSRB->TotalXferredLen, pSRB->SGToBeXferLen);
+			    )
+		}
 	}
-    }
-    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 }
 
-void
-dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_Command_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    UCHAR   sstatus, residual, bval;
-    PSGL    psgl;
-    ULONG   ResidCnt, xferCnt, i;
-    PUCHAR  ptr;
+}
 
-    sstatus = *psstatus;
+static void dc390_Status_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
 
-    if( !(pSRB->SRBState & SRB_XFERPAD) )
-    {
-	if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
-	    pSRB->SRBStatus |= PARITY_ERROR;
+	pSRB->TargetStatus = DC390_read8(ScsiFifo);
+	//udelay (1);
+	pSRB->EndMessage = DC390_read8(ScsiFifo);	/* get message */
 
-	if( sstatus & COUNT_2_ZERO )
-	{
-	    int ctr = 5000000; /* only try for about a tenth of a second */
-	    int dstate = 0;
-	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
-	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
-	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
-	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
-	    DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16)	\
-		+ ((ULONG) DC390_read8 (CtcReg_Mid) << 8)		\
-		+ ((ULONG) DC390_read8 (CtcReg_Low));)
-	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
-
-	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
-
-	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
-	    pSRB->SGIndex++;
-	    if( pSRB->SGIndex < pSRB->SGcount )
-	    {
-		pSRB->pSegmentList++;
-		psgl = pSRB->pSegmentList;
-
-		pSRB->SGBusAddr = virt_to_bus( psgl->address );
-		pSRB->SGToBeXferLen = (ULONG) psgl->length;
-	    }
-	    else
-		pSRB->SGToBeXferLen = 0;
-	}
-	else	/* phase changed */
-	{
-	    residual = 0;
-	    bval = DC390_read8 (Current_Fifo);
-	    while( bval & 0x1f )
-	    {
-		DEBUG1(printk (KERN_DEBUG "Check for residuals,");)
-		if( (bval & 0x1f) == 1 )
-		{
-		    for(i=0; i < 0x100; i++)
-		    {
-			bval = DC390_read8 (Current_Fifo);
-			if( !(bval & 0x1f) )
-			    goto din_1;
-			else if( i == 0x0ff )
-			{
-			    residual = 1;   /* ;1 residual byte */
-			    goto din_1;
-			}
-		    }
-		}
-		else
-		    bval = DC390_read8 (Current_Fifo);
-	    }
-din_1:
-	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
-	    for (i = 0xa000; i; i--)
-	    {
-		bval = DC390_read8 (DMA_Status);
-		if (bval & BLAST_COMPLETE)
-		    break;
-	    }
-	    /* It seems a DMA Blast abort isn't that bad ... */
-	    if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
-	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
-	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
-
-	    DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);)
-	    ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
-	    ResidCnt <<= 8;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
-	    ResidCnt <<= 8;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low);
-
-	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
-	    pSRB->SGBusAddr += xferCnt;
-	    pSRB->TotalXferredLen += xferCnt;
-	    pSRB->SGToBeXferLen = ResidCnt;
-
-	    if( residual )
-	    {
-		bval = DC390_read8 (ScsiFifo);	    /* get one residual byte */
-		ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr );
-		*ptr = bval;
-		pSRB->SGBusAddr++; xferCnt++;
-		pSRB->TotalXferredLen++;
-		pSRB->SGToBeXferLen--;
-	    }
-	    DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
-			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen);)
-
-	}
-    }
-}
-
-static void
-dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
-{
-}
-
-static void
-dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
-{
-
-    pSRB->TargetStatus = DC390_read8 (ScsiFifo);
-    //udelay (1);
-    pSRB->EndMessage = DC390_read8 (ScsiFifo);	/* get message */
-
-    *psstatus = SCSI_NOP0;
-    pSRB->SRBState = SRB_COMPLETED;
-    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+	*psstatus = SCSI_NOP0;
+	pSRB->SRBState = SRB_COMPLETED;
+	DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD);
 }
 
-static void
-dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_MsgOut_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
-	*psstatus = SCSI_NOP0;
-    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+	if (pSRB->SRBState & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
+		*psstatus = SCSI_NOP0;
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
 
 static void __inline__
-dc390_reprog (PACB pACB, PDCB pDCB)
+ dc390_reprog(PACB pACB, PDCB pDCB)
 {
-  DC390_write8 (Sync_Period, pDCB->SyncPeriod);
-  DC390_write8 (Sync_Offset, pDCB->SyncOffset);
-  DC390_write8 (CtrlReg3, pDCB->CtrlR3);
-  DC390_write8 (CtrlReg4, pDCB->CtrlR4);
-  dc390_SetXferRate (pACB, pDCB);
+	DC390_write8(Sync_Period, pDCB->SyncPeriod);
+	DC390_write8(Sync_Offset, pDCB->SyncOffset);
+	DC390_write8(CtrlReg3, pDCB->CtrlR3);
+	DC390_write8(CtrlReg4, pDCB->CtrlR4);
+	dc390_SetXferRate(pACB, pDCB);
 };
 
 
 #ifdef DC390_DEBUG0
-static void
-dc390_printMsg (UCHAR *MsgBuf, UCHAR len)
+static void dc390_printMsg(UCHAR * MsgBuf, UCHAR len)
 {
-  int i;
-  printk (" %02x", MsgBuf[0]);
-  for (i = 1; i < len; i++)
-    printk (" %02x", MsgBuf[i]);
-  printk ("\n");
+	int i;
+	printk(" %02x", MsgBuf[0]);
+	for (i = 1; i < len; i++)
+		printk(" %02x", MsgBuf[i]);
+	printk("\n");
 };
 #endif
 
@@ -591,151 +565,147 @@
 
 /* reject_msg */
 static void __inline__
-dc390_MsgIn_reject (PACB pACB, PSRB pSRB)
+ dc390_MsgIn_reject(PACB pACB, PSRB pSRB)
 {
-  pSRB->MsgOutBuf[0] = MSG_REJECT_;
-  pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
-  DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");)
+	pSRB->MsgOutBuf[0] = MSG_REJECT_;
+	pSRB->MsgCnt = 1;
+	DC390_ENABLE_MSGOUT;
+	DEBUG0(printk(KERN_INFO "DC390: Reject message\n");
+	    )
 }
 
 /* abort command */
 static void __inline__
-dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB )
+ dc390_EnableMsgOut_Abort(PACB pACB, PSRB pSRB)
 {
-    pSRB->MsgOutBuf[0] = MSG_ABORT; 
-    pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
-    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
+	pSRB->MsgOutBuf[0] = MSG_ABORT;
+	pSRB->MsgCnt = 1;
+	DC390_ENABLE_MSGOUT;
+	pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
 }
 
 static PSRB
-dc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag)
+ dc390_MsgIn_QTag(PACB pACB, PDCB pDCB, UCHAR tag)
 {
-  PSRB lastSRB = pDCB->pGoingLast;
-  PSRB pSRB = pDCB->pGoingSRB;
+	PSRB lastSRB = pDCB->pGoingLast;
+	PSRB pSRB = pDCB->pGoingSRB;
 
-  if (pSRB)
-    {
-      for( ;pSRB ; )
-	{
-	  if (pSRB->TagNumber == tag) break;
-	  if (pSRB == lastSRB) goto mingx0;
-	  pSRB = pSRB->pNextSRB;
-	}
-
-      if( pDCB->DCBFlag & ABORT_DEV_ )
-	{
-	  pSRB->SRBState = SRB_ABORT_SENT;
-	  dc390_EnableMsgOut_Abort( pACB, pSRB );
-	}
+	if (pSRB) {
+		for (; pSRB;) {
+			if (pSRB->TagNumber == tag)
+				break;
+			if (pSRB == lastSRB)
+				goto mingx0;
+			pSRB = pSRB->pNextSRB;
+		}
 
-      if( !(pSRB->SRBState & SRB_DISCONNECT) )
-	goto  mingx0;
+		if (pDCB->DCBFlag & ABORT_DEV_) {
+			pSRB->SRBState = SRB_ABORT_SENT;
+			dc390_EnableMsgOut_Abort(pACB, pSRB);
+		}
+		if (!(pSRB->SRBState & SRB_DISCONNECT))
+			goto mingx0;
 
-      pDCB->pActiveSRB = pSRB;
-      pSRB->SRBState = SRB_DATA_XFER;
-    }
-  else
-    {
-    mingx0:
-      pSRB = pACB->pTmpSRB;
-      pSRB->SRBState = SRB_UNEXPECT_RESEL;
-      pDCB->pActiveSRB = pSRB;
-      pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
-      pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
-    }
-  return pSRB;
+		pDCB->pActiveSRB = pSRB;
+		pSRB->SRBState = SRB_DATA_XFER;
+	} else {
+	      mingx0:
+		pSRB = pACB->pTmpSRB;
+		pSRB->SRBState = SRB_UNEXPECT_RESEL;
+		pDCB->pActiveSRB = pSRB;
+		pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+		pSRB->MsgCnt = 1;
+		DC390_ENABLE_MSGOUT;
+	}
+	return pSRB;
 }
 
 
 /* set async transfer mode */
-static void 
-dc390_MsgIn_set_async (PACB pACB, PSRB pSRB)
+static void dc390_MsgIn_set_async(PACB pACB, PSRB pSRB)
 {
-  PDCB pDCB = pSRB->pSRBDCB;
-  if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
-    printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID);
-  pSRB->SRBState &= ~DO_SYNC_NEGO;
-  pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
-  pDCB->SyncPeriod = 0;
-  pDCB->SyncOffset = 0;
-  //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
-  pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
-  pDCB->CtrlR4 &= 0x3f;
-  pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
-  dc390_reprog (pACB, pDCB);
+	PDCB pDCB = pSRB->pSRBDCB;
+	if (!(pSRB->SRBState & DO_SYNC_NEGO))
+		printk("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID);
+	pSRB->SRBState &= ~DO_SYNC_NEGO;
+	pDCB->SyncMode &= ~(SYNC_ENABLE + SYNC_NEGO_DONE);
+	pDCB->SyncPeriod = 0;
+	pDCB->SyncOffset = 0;
+	//pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+	pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
+	pDCB->CtrlR4 &= 0x3f;
+	pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+	dc390_reprog(pACB, pDCB);
 }
 
 /* set sync transfer mode */
-static void
-dc390_MsgIn_set_sync (PACB pACB, PSRB pSRB)
+static void dc390_MsgIn_set_sync(PACB pACB, PSRB pSRB)
 {
-  UCHAR bval;
-  USHORT wval, wval1;
-  PDCB pDCB = pSRB->pSRBDCB;
-  UCHAR oldsyncperiod = pDCB->SyncPeriod;
-  UCHAR oldsyncoffset = pDCB->SyncOffset;
-  
-  if (!(pSRB->SRBState & DO_SYNC_NEGO))
-    {
-      printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
-	      pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
-
-      /* reject */
-      //dc390_MsgIn_reject (pACB, pSRB);
-      //return dc390_MsgIn_set_async (pACB, pSRB);
-
-      /* Reply with corrected SDTR Message */
-      if (pSRB->MsgInBuf[4] > 15)
-	{ 
-	  printk ("DC390: Lower Sync Offset to 15\n");
-	  pSRB->MsgInBuf[4] = 15;
-	}
-      if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
-	{
-	  printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
-	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
+	UCHAR bval;
+	USHORT wval, wval1;
+	PDCB pDCB = pSRB->pSRBDCB;
+	UCHAR oldsyncperiod = pDCB->SyncPeriod;
+	UCHAR oldsyncoffset = pDCB->SyncOffset;
+
+	if (!(pSRB->SRBState & DO_SYNC_NEGO)) {
+		printk("DC390: Target %i initiates Sync: %ins %i ... answer ...\n",
+		       pDCB->UnitSCSIID, pSRB->MsgInBuf[3] << 2, pSRB->MsgInBuf[4]);
+
+		/* reject */
+		//dc390_MsgIn_reject (pACB, pSRB);
+		//return dc390_MsgIn_set_async (pACB, pSRB);
+
+		/* Reply with corrected SDTR Message */
+		if (pSRB->MsgInBuf[4] > 15) {
+			printk("DC390: Lower Sync Offset to 15\n");
+			pSRB->MsgInBuf[4] = 15;
+		}
+		if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) {
+			printk("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
+			pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
+		};
+		memcpy(pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
+		pSRB->MsgCnt = 5;
+		DC390_ENABLE_MSGOUT;
 	};
-      memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
-      pSRB->MsgCnt = 5;
-      DC390_ENABLE_MSGOUT;
-    };
-
-  pSRB->SRBState &= ~DO_SYNC_NEGO;
-  pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
-  pDCB->SyncOffset &= 0x0f0;
-  pDCB->SyncOffset |= pSRB->MsgInBuf[4];
-  pDCB->NegoPeriod = pSRB->MsgInBuf[3];
-
-  wval = (USHORT) pSRB->MsgInBuf[3];
-  wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
-  if( (wval1 * 25) != wval) wval1++;
-  bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
-
-  pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
-  if (pACB->glitch_cfg != NS_TO_GLITCH(0))
-    pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
-  else
-    pDCB->CtrlR4 |= NS_TO_GLITCH(0);
-  if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
-
-  if (wval1 >= 8)
-    {
-      wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
-      bval = FAST_CLK;		/* fast clock / normal scsi */
-      pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
-    }
-
-  pDCB->CtrlR3 = bval;
-  pDCB->SyncPeriod = (UCHAR)wval1;
-  
-  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0)
-    {
-      if (! (bval & FAST_SCSI)) wval1++;
-      printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, 
-	      40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
-    }
-  
-  dc390_reprog (pACB, pDCB);
+
+	pSRB->SRBState &= ~DO_SYNC_NEGO;
+	pDCB->SyncMode |= SYNC_ENABLE + SYNC_NEGO_DONE;
+	pDCB->SyncOffset &= 0x0f0;
+	pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+	pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+
+	wval = (USHORT) pSRB->MsgInBuf[3];
+	wval = wval << 2;
+	wval -= 3;
+	wval1 = wval / 25;	/* compute speed */
+	if ((wval1 * 25) != wval)
+		wval1++;
+	bval = FAST_CLK + FAST_SCSI;	/* fast clock / fast scsi */
+
+	pDCB->CtrlR4 &= 0x3f;	/* Glitch eater: 12ns less than normal */
+	if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+		pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+	else
+		pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+	if (wval1 < 4)
+		pDCB->CtrlR4 |= NS_TO_GLITCH(0);	/* Ultra */
+
+	if (wval1 >= 8) {
+		wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
+		bval = FAST_CLK;	/* fast clock / normal scsi */
+		pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+	}
+	pDCB->CtrlR3 = bval;
+	pDCB->SyncPeriod = (UCHAR) wval1;
+
+	if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0) {
+		if (!(bval & FAST_SCSI))
+			wval1++;
+		printk("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID,
+		       40 / wval1, ((40 % wval1) * 10 + wval1 / 2) / wval1, pDCB->SyncOffset & 0x0f);
+	}
+	dc390_reprog(pACB, pDCB);
 };
 
 
@@ -749,969 +719,890 @@
 
 /* Check if the message is complete */
 static UCHAR __inline__
-dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len)
-{ 
-  if (*msgbuf == MSG_EXTENDED)
-    {
-      if (len < 2) return 0;
-      if (len < msgbuf[1] + 2) return 0;
-    }
-  else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
-    if (len < 2) return 0;
-  return 1;
+ dc390_MsgIn_complete(UCHAR * msgbuf, ULONG len)
+{
+	if (*msgbuf == MSG_EXTENDED) {
+		if (len < 2)
+			return 0;
+		if (len < msgbuf[1] + 2)
+			return 0;
+	} else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f)	// two byte messages
+
+		if (len < 2)
+			return 0;
+	return 1;
 }
 
 
 
 /* read and eval received messages */
-void
-dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void dc390_MsgIn_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    PDCB   pDCB = pACB->pActiveDCB;
+	PDCB pDCB = pACB->pActiveDCB;
 
-    /* Read the msg */
+	/* Read the msg */
 
-    pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo);
-    //pSRB->SRBState = 0;
-
-    /* Msg complete ? */
-    if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
-      {
-	DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen);)
-	/* Now eval the msg */
-	switch (pSRB->MsgInBuf[0]) 
-	  {
-	  case MSG_DISCONNECT: 
-	    pSRB->SRBState = SRB_DISCONNECT; break;
-	    
-	  case MSG_SIMPLE_QTAG:
-	  case MSG_HEAD_QTAG:
-	  case MSG_ORDER_QTAG:
-	    pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
-	    break;
-	    
-	  case MSG_REJECT_: 
-	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
-	    pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
-	    if( pSRB->SRBState & DO_SYNC_NEGO)
-	      dc390_MsgIn_set_async (pACB, pSRB);
-	    break;
-	    
-	  case MSG_EXTENDED:
-	    /* reject every extended msg but SDTR */
-	    if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
-	      dc390_MsgIn_reject (pACB, pSRB);
-	    else
-	      {
-		if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
-		  dc390_MsgIn_set_async (pACB, pSRB);
-		else
-		  dc390_MsgIn_set_sync (pACB, pSRB);
-	      };
-	    
-	    // nothing has to be done
-	  case MSG_COMPLETE: break;
-	    
-	    // SAVE POINTER my be ignored as we have the PSRB associated with the
-	    // scsi command. Thanks, Gerard, for pointing it out.
-	  case MSG_SAVE_PTR: break;
-	    // The device might want to restart transfer with a RESTORE
-	  case MSG_RESTORE_PTR: 
-	    printk ("DC390: RESTORE POINTER message received ... reject\n");
-	    // fall through
-
-	    // reject unknown messages
-	  default: dc390_MsgIn_reject (pACB, pSRB);
-	  }
-	
-	/* Clear counter and MsgIn state */
-	pSRB->SRBState &= ~SRB_MSGIN;
-	pACB->MsgLen = 0;
-      };
+	pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8(ScsiFifo);
+	//pSRB->SRBState = 0;
 
-    *psstatus = SCSI_NOP0;
-    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
-    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+	/* Msg complete ? */
+	if (dc390_MsgIn_complete(pSRB->MsgInBuf, pACB->MsgLen)) {
+		DEBUG0(printk(KERN_INFO "DC390: MsgIn:");
+		       dc390_printMsg(pSRB->MsgInBuf, pACB->MsgLen);
+		    )
+		/* Now eval the msg */
+		    switch (pSRB->MsgInBuf[0]) {
+		case MSG_DISCONNECT:
+			pSRB->SRBState = SRB_DISCONNECT;
+			break;
+
+		case MSG_SIMPLE_QTAG:
+		case MSG_HEAD_QTAG:
+		case MSG_ORDER_QTAG:
+			pSRB = dc390_MsgIn_QTag(pACB, pDCB, pSRB->MsgInBuf[1]);
+			break;
+
+		case MSG_REJECT_:
+			DC390_write8(ScsiCmd, RESET_ATN_CMD);
+			pDCB->NegoPeriod = 50;	/* 200ns <=> 5 MHz */
+			if (pSRB->SRBState & DO_SYNC_NEGO)
+				dc390_MsgIn_set_async(pACB, pSRB);
+			break;
+
+		case MSG_EXTENDED:
+			/* reject every extended msg but SDTR */
+			if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
+				dc390_MsgIn_reject(pACB, pSRB);
+			else {
+				if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
+					dc390_MsgIn_set_async(pACB, pSRB);
+				else
+					dc390_MsgIn_set_sync(pACB, pSRB);
+			};
+
+			// nothing has to be done
+		case MSG_COMPLETE:
+			break;
+
+			// SAVE POINTER my be ignored as we have the PSRB associated with the
+			// scsi command. Thanks, Gerard, for pointing it out.
+		case MSG_SAVE_PTR:
+			break;
+			// The device might want to restart transfer with a RESTORE
+		case MSG_RESTORE_PTR:
+			printk("DC390: RESTORE POINTER message received ... reject\n");
+			// fall through
+
+			// reject unknown messages
+		default:
+			dc390_MsgIn_reject(pACB, pSRB);
+		}
+
+		/* Clear counter and MsgIn state */
+		pSRB->SRBState &= ~SRB_MSGIN;
+		pACB->MsgLen = 0;
+	};
+
+	*psstatus = SCSI_NOP0;
+	DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD);
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
 
-void
-dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
+void dc390_DataIO_Comm(PACB pACB, PSRB pSRB, UCHAR ioDir)
 {
-    PSGL   psgl;
-    ULONG  lval;
+	PSGL psgl;
+	ULONG lval;
 
-    if( pSRB->SGIndex < pSRB->SGcount )
-    {
-	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
-	if( !pSRB->SGToBeXferLen )
-	{
-	    psgl = pSRB->pSegmentList;
-	    pSRB->SGBusAddr = virt_to_bus( psgl->address );
-	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
-	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");)
-	}
-	lval = pSRB->SGToBeXferLen;
-	DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
-	DC390_write8 (CtcReg_Low, (UCHAR) lval);
-	lval >>= 8;
-	DC390_write8 (CtcReg_Mid, (UCHAR) lval);
-	lval >>= 8;
-	DC390_write8 (CtcReg_High, (UCHAR) lval);
-
-	DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
-	DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
-
-	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
-	pSRB->SRBState = SRB_DATA_XFER;
-
-	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
-
-	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
-	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);)
-	//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
-	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);)
-    }
-    else    /* xfer pad */
-    {
-	if( pSRB->SGcount )
-	{
-	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
-	    pSRB->SRBStatus |= OVER_RUN;
-	    DEBUG0(printk (KERN_WARNING " DC390: Overrun -");)
-	}
-	DEBUG0(printk (KERN_WARNING " Clear transfer pad \n");)
-	DC390_write8 (CtcReg_Low, 0);
-	DC390_write8 (CtcReg_Mid, 0);
-	DC390_write8 (CtcReg_High, 0);
+	if (pSRB->SGIndex < pSRB->SGcount) {
+		DC390_write8(DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */ );
+		if (!pSRB->SGToBeXferLen) {
+			psgl = pSRB->pSegmentList;
+			pSRB->SGBusAddr = virt_to_bus(psgl->address);
+			pSRB->SGToBeXferLen = (ULONG) psgl->length;
+			DEBUG1(printk(KERN_DEBUG " DC390: Next SG segment.");
+			    )
+		}
+		lval = pSRB->SGToBeXferLen;
+		DEBUG1(printk(KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);
+		    )
+		    DC390_write8(CtcReg_Low, (UCHAR) lval);
+		lval >>= 8;
+		DC390_write8(CtcReg_Mid, (UCHAR) lval);
+		lval >>= 8;
+		DC390_write8(CtcReg_High, (UCHAR) lval);
+
+		DC390_write32(DMA_XferCnt, pSRB->SGToBeXferLen);
+		DC390_write32(DMA_XferAddr, pSRB->SGBusAddr);
+
+		//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+		pSRB->SRBState = SRB_DATA_XFER;
+
+		DC390_write8(ScsiCmd, DMA_COMMAND + INFO_XFER_CMD);
+
+		DC390_write8(DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+		//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);)
+		//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
+		//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);)
+	} else {		/* xfer pad */
+		if (pSRB->SGcount) {
+			pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+			pSRB->SRBStatus |= OVER_RUN;
+			DEBUG0(printk(KERN_WARNING " DC390: Overrun -");
+			    )
+		}
+		DEBUG0(printk(KERN_WARNING " Clear transfer pad \n");
+		    )
+		    DC390_write8(CtcReg_Low, 0);
+		DC390_write8(CtcReg_Mid, 0);
+		DC390_write8(CtcReg_High, 0);
 
-	pSRB->SRBState |= SRB_XFERPAD;
-	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
+		pSRB->SRBState |= SRB_XFERPAD;
+		DC390_write8(ScsiCmd, DMA_COMMAND + XFER_PAD_BYTE);
 /*
-	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
-	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
-*/
-    }
+   DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
+   DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+ */
+	}
 }
 
 
-static void
-dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_DataOutPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+	dc390_DataIO_Comm(pACB, pSRB, WRITE_DIRECTION);
+}
+
+static void dc390_DataInPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+	dc390_DataIO_Comm(pACB, pSRB, READ_DIRECTION);
+}
+
+void dc390_CommandPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
+	PDCB pDCB;
+	UCHAR i, cnt;
+	PUCHAR ptr;
+
+	DC390_write8(ScsiCmd, RESET_ATN_CMD);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+	if (!(pSRB->SRBFlag & AUTO_REQSENSE)) {
+		cnt = (UCHAR) pSRB->ScsiCmdLen;
+		ptr = (PUCHAR) pSRB->CmdBlock;
+		for (i = 0; i < cnt; i++)
+			DC390_write8(ScsiFifo, *(ptr++));
+	} else {
+		UCHAR bval = 0;
+		DC390_write8(ScsiFifo, REQUEST_SENSE);
+		pDCB = pACB->pActiveDCB;
+		DC390_write8(ScsiFifo, pDCB->IdentifyMsg << 5);
+		DC390_write8(ScsiFifo, bval);
+		DC390_write8(ScsiFifo, bval);
+		DC390_write8(ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+		DC390_write8(ScsiFifo, bval);
+	}
+	pSRB->SRBState = SRB_COMMAND;
+	DC390_write8(ScsiCmd, INFO_XFER_CMD);
 }
 
-static void
-dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_StatusPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+	pSRB->SRBState = SRB_STATUS;
+	DC390_write8(ScsiCmd, INITIATOR_CMD_CMPLTE);
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-void
-dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+void dc390_MsgOutPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    PDCB   pDCB;
-    UCHAR  i, cnt;
-    PUCHAR ptr;
+	UCHAR bval, i, cnt;
+	PUCHAR ptr;
+	PDCB pDCB;
 
-    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
-    {
-	cnt = (UCHAR) pSRB->ScsiCmdLen;
-	ptr = (PUCHAR) pSRB->CmdBlock;
-	for(i=0; i < cnt; i++)
-	    DC390_write8 (ScsiFifo, *(ptr++));
-    }
-    else
-    {
-	UCHAR bval = 0;
-	DC390_write8 (ScsiFifo, REQUEST_SENSE);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
 	pDCB = pACB->pActiveDCB;
-	DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
-	DC390_write8 (ScsiFifo, bval);
-	DC390_write8 (ScsiFifo, bval);
-	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
-	DC390_write8 (ScsiFifo, bval);
-    }
-    pSRB->SRBState = SRB_COMMAND;
-    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
-}
-
-static void
-dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
-{
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    pSRB->SRBState = SRB_STATUS;
-    DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
-    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-}
-
-void
-dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
-{
-    UCHAR   bval, i, cnt;
-    PUCHAR  ptr;
-    PDCB    pDCB;
-
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    pDCB = pACB->pActiveDCB;
-    if( !(pSRB->SRBState & SRB_MSGOUT) )
-    {
-	cnt = pSRB->MsgCnt;
-	if( cnt )
-	{
-	    ptr = (PUCHAR) pSRB->MsgOutBuf;
-	    for(i=0; i < cnt; i++)
-		DC390_write8 (ScsiFifo, *(ptr++));
-	    pSRB->MsgCnt = 0;
-	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
-		(pSRB->MsgOutBuf[0] == MSG_ABORT) )
-		pSRB->SRBState = SRB_ABORT_SENT;
+	if (!(pSRB->SRBState & SRB_MSGOUT)) {
+		cnt = pSRB->MsgCnt;
+		if (cnt) {
+			ptr = (PUCHAR) pSRB->MsgOutBuf;
+			for (i = 0; i < cnt; i++)
+				DC390_write8(ScsiFifo, *(ptr++));
+			pSRB->MsgCnt = 0;
+			if ((pDCB->DCBFlag & ABORT_DEV_) &&
+			    (pSRB->MsgOutBuf[0] == MSG_ABORT))
+				pSRB->SRBState = SRB_ABORT_SENT;
+		} else {
+			bval = MSG_ABORT;	/* ??? MSG_NOP */
+			if ((pSRB->CmdBlock[0] == INQUIRY) ||
+			    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+			    (pSRB->SRBFlag & AUTO_REQSENSE)) {
+				if (pDCB->SyncMode & SYNC_ENABLE)
+					goto mop1;
+			}
+			DC390_write8(ScsiFifo, bval);
+		}
+		DC390_write8(ScsiCmd, INFO_XFER_CMD);
+	} else {
+	      mop1:
+		//printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+		DC390_write8(ScsiFifo, MSG_EXTENDED);
+		DC390_write8(ScsiFifo, 3);	/*    ;length of extended msg */
+		DC390_write8(ScsiFifo, EXTENDED_SDTR);	/*    ; sync nego */
+		DC390_write8(ScsiFifo, pDCB->NegoPeriod);
+		if (pDCB->SyncOffset & 0x0f)
+			DC390_write8(ScsiFifo, pDCB->SyncOffset);
+		else
+			DC390_write8(ScsiFifo, SYNC_NEGO_OFFSET);
+		pSRB->SRBState |= DO_SYNC_NEGO;
+		DC390_write8(ScsiCmd, INFO_XFER_CMD);
 	}
-	else
-	{
-	    bval = MSG_ABORT;	/* ??? MSG_NOP */
-	    if( (pSRB->CmdBlock[0] == INQUIRY ) ||
-		(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
-		(pSRB->SRBFlag & AUTO_REQSENSE) )
-	    {
-		if( pDCB->SyncMode & SYNC_ENABLE )
-		    goto  mop1;
-	    }
-	    DC390_write8 (ScsiFifo, bval);
-	}
-	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
-    }
-    else
-    {
-mop1:
-	//printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
-	DC390_write8 (ScsiFifo, MSG_EXTENDED);
-	DC390_write8 (ScsiFifo, 3);	/*    ;length of extended msg */
-	DC390_write8 (ScsiFifo, EXTENDED_SDTR);	/*    ; sync nego */
-	DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
-	if (pDCB->SyncOffset & 0x0f)
-		    DC390_write8 (ScsiFifo, pDCB->SyncOffset);
-	else
-		    DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);		    
-	pSRB->SRBState |= DO_SYNC_NEGO;
-	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
-    }
 }
 
-static void
-dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_MsgInPhase(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    if( !(pSRB->SRBState & SRB_MSGIN) )
-    {
-	pSRB->SRBState &= ~SRB_DISCONNECT;
-	pSRB->SRBState |= SRB_MSGIN;
-    }
-    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
-    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+	if (!(pSRB->SRBState & SRB_MSGIN)) {
+		pSRB->SRBState &= ~SRB_DISCONNECT;
+		pSRB->SRBState |= SRB_MSGIN;
+	}
+	DC390_write8(ScsiCmd, INFO_XFER_CMD);
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-static void
-dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_Nop_0(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
-static void
-dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+static void dc390_Nop_1(PACB pACB, PSRB pSRB, PUCHAR psstatus)
 {
 }
 
 
-static void
-dc390_SetXferRate( PACB pACB, PDCB pDCB )
+static void dc390_SetXferRate(PACB pACB, PDCB pDCB)
 {
-    UCHAR  bval, i, cnt;
-    PDCB   ptr;
+	UCHAR bval, i, cnt;
+	PDCB ptr;
 
-    if( !(pDCB->IdentifyMsg & 0x07) )
-    {
-	if( pACB->scan_devices )
-	{
-	    dc390_CurrSyncOffset = pDCB->SyncOffset;
+	if (!(pDCB->IdentifyMsg & 0x07)) {
+		if (pACB->scan_devices) {
+			dc390_CurrSyncOffset = pDCB->SyncOffset;
+		} else {
+			ptr = pACB->pLinkDCB;
+			cnt = pACB->DCBCnt;
+			bval = pDCB->UnitSCSIID;
+			for (i = 0; i < cnt; i++) {
+				if (ptr->UnitSCSIID == bval) {
+					ptr->SyncPeriod = pDCB->SyncPeriod;
+					ptr->SyncOffset = pDCB->SyncOffset;
+					ptr->CtrlR3 = pDCB->CtrlR3;
+					ptr->CtrlR4 = pDCB->CtrlR4;
+					ptr->SyncMode = pDCB->SyncMode;
+				}
+				ptr = ptr->pNextDCB;
+			}
+		}
 	}
-	else
-	{
-	    ptr = pACB->pLinkDCB;
-	    cnt = pACB->DCBCnt;
-	    bval = pDCB->UnitSCSIID;
-	    for(i=0; i<cnt; i++)
-	    {
-		if( ptr->UnitSCSIID == bval )
-		{
-		    ptr->SyncPeriod = pDCB->SyncPeriod;
-		    ptr->SyncOffset = pDCB->SyncOffset;
-		    ptr->CtrlR3 = pDCB->CtrlR3;
-		    ptr->CtrlR4 = pDCB->CtrlR4;
-		    ptr->SyncMode = pDCB->SyncMode;
-		}
-		ptr = ptr->pNextDCB;
-	    }
-	}
-    }
-    return;
+	return;
 }
 
 
-void
-dc390_Disconnect( PACB pACB )
-{
-    PDCB   pDCB;
-    PSRB   pSRB, psrb;
-    UCHAR  i, cnt;
-
-    DEBUG0(printk(KERN_INFO "DISC,");)
-
-    pDCB = pACB->pActiveDCB;
-    if (!pDCB)
-     {
-	int j = 400;
-	DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\
-	       (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);)
-	while (--j) udelay (1000);
-	DC390_read8 (INT_Status);	/* Reset Pending INT */
-	DC390_write8 (ScsiCmd, EN_SEL_RESEL);
-	return;
-     }
-    pSRB = pDCB->pActiveSRB;
-    pACB->pActiveDCB = 0;
-    pSRB->ScsiPhase = SCSI_NOP0;
-    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
-    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
-    {
-	pSRB->SRBState = 0;
-	dc390_DoWaitingSRB( pACB );
-    }
-    else if( pSRB->SRBState & SRB_ABORT_SENT )
-    {
-	pDCB->TagMask = 0;
-	pDCB->DCBFlag = 0;
-	cnt = pDCB->GoingSRBCnt;
-	pDCB->GoingSRBCnt = 0;
-	pSRB = pDCB->pGoingSRB;
-	for( i=0; i < cnt; i++)
-	{
-	    psrb = pSRB->pNextSRB;
-	    pSRB->pNextSRB = pACB->pFreeSRB;
-	    pACB->pFreeSRB = pSRB;
-	    pSRB = psrb;
-	}
-	pDCB->pGoingSRB = 0;
-	dc390_DoWaitingSRB( pACB );
-    }
-    else
-    {
-	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
-	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
-	{	/* Selection time out */
-	    if( !(pACB->scan_devices) )
-	    {
-		pSRB->SRBState = SRB_READY;
-		dc390_RewaitSRB( pDCB, pSRB);
-	    }
-	    else
-	    {
-		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
-		goto  disc1;
-	    }
+void dc390_Disconnect(PACB pACB)
+{
+	PDCB pDCB;
+	PSRB pSRB, psrb;
+	UCHAR i, cnt;
+
+	DEBUG0(printk(KERN_INFO "DISC,");
+	    )
+	    pDCB = pACB->pActiveDCB;
+	if (!pDCB) {
+		int j = 400;
+		DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n", \
+			      (ULONG) pACB, (ULONG) pDCB, pACB->IOPortBase, pACB->IRQLevel);
+		    )
+		    while (--j)
+			udelay(1000);
+		DC390_read8(INT_Status);	/* Reset Pending INT */
+		DC390_write8(ScsiCmd, EN_SEL_RESEL);
+		return;
 	}
-	else if( pSRB->SRBState & SRB_DISCONNECT )
-	{
-	    dc390_DoWaitingSRB( pACB );
+	pSRB = pDCB->pActiveSRB;
+	pACB->pActiveDCB = 0;
+	pSRB->ScsiPhase = SCSI_NOP0;
+	DC390_write8(ScsiCmd, EN_SEL_RESEL);
+	if (pSRB->SRBState & SRB_UNEXPECT_RESEL) {
+		pSRB->SRBState = 0;
+		dc390_DoWaitingSRB(pACB);
+	} else if (pSRB->SRBState & SRB_ABORT_SENT) {
+		pDCB->TagMask = 0;
+		pDCB->DCBFlag = 0;
+		cnt = pDCB->GoingSRBCnt;
+		pDCB->GoingSRBCnt = 0;
+		pSRB = pDCB->pGoingSRB;
+		for (i = 0; i < cnt; i++) {
+			psrb = pSRB->pNextSRB;
+			pSRB->pNextSRB = pACB->pFreeSRB;
+			pACB->pFreeSRB = pSRB;
+			pSRB = psrb;
+		}
+		pDCB->pGoingSRB = 0;
+		dc390_DoWaitingSRB(pACB);
+	} else {
+		if ((pSRB->SRBState & (SRB_START_ + SRB_MSGOUT)) ||
+		  !(pSRB->SRBState & (SRB_DISCONNECT + SRB_COMPLETED))) {	/* Selection time out */
+			if (!(pACB->scan_devices)) {
+				pSRB->SRBState = SRB_READY;
+				dc390_RewaitSRB(pDCB, pSRB);
+			} else {
+				pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+				goto disc1;
+			}
+		} else if (pSRB->SRBState & SRB_DISCONNECT) {
+			dc390_DoWaitingSRB(pACB);
+		} else if (pSRB->SRBState & SRB_COMPLETED) {
+		      disc1:
+			if (pDCB->MaxCommand > 1) {
+				pDCB->TagMask &= (~(1 << pSRB->TagNumber));	/* free tag mask */
+			}
+			pDCB->pActiveSRB = 0;
+			pSRB->SRBState = SRB_FREE;
+			dc390_SRBdone(pACB, pDCB, pSRB);
+		}
 	}
-	else if( pSRB->SRBState & SRB_COMPLETED )
-	{
-disc1:
-	    if(pDCB->MaxCommand > 1)
-	    {
-	       pDCB->TagMask &= (~(1 << pSRB->TagNumber));   /* free tag mask */
-	    }
-	    pDCB->pActiveSRB = 0;
-	    pSRB->SRBState = SRB_FREE;
-	    dc390_SRBdone( pACB, pDCB, pSRB);
-	}
-    }
-    pACB->MsgLen = 0;
+	pACB->MsgLen = 0;
 }
 
 
-void
-dc390_Reselect( PACB pACB )
-{
-    PDCB   pDCB;
-    PSRB   pSRB;
-    USHORT wval;
-    UCHAR  bval;
-
-    DEBUG0(printk(KERN_INFO "RSEL,");)
-    pDCB = pACB->pActiveDCB;
-    if( pDCB )
-    {	/* Arbitration lost but Reselection won */
-	DEBUG0(printk ("(ActiveDCB != 0)");)
-	pSRB = pDCB->pActiveSRB;
-	if( !( pACB->scan_devices ) )
-	{
-	    pSRB->SRBState = SRB_READY;
-	    dc390_RewaitSRB( pDCB, pSRB);
+void dc390_Reselect(PACB pACB)
+{
+	PDCB pDCB;
+	PSRB pSRB;
+	USHORT wval;
+	UCHAR bval;
+
+	DEBUG0(printk(KERN_INFO "RSEL,");
+	    )
+	    pDCB = pACB->pActiveDCB;
+	if (pDCB) {		/* Arbitration lost but Reselection won */
+		DEBUG0(printk("(ActiveDCB != 0)");
+		    )
+		    pSRB = pDCB->pActiveSRB;
+		if (!(pACB->scan_devices)) {
+			pSRB->SRBState = SRB_READY;
+			dc390_RewaitSRB(pDCB, pSRB);
+		}
 	}
-    }
-    bval = DC390_read8 (ScsiFifo);	/* get ID */
-    DEBUG0(printk ("Dev %02x,", bval);)
-    bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
-    wval = 0;
-    while (bval >>= 1) wval++;
-    wval |=  ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8;  /* get LUN */
-    DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);)
-    pDCB = pACB->pLinkDCB;
-    while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
-    {
-	pDCB = pDCB->pNextDCB;
-	if( pDCB == pACB->pLinkDCB )
-	 {
-	    printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n",
-		    wval & 0xff, (wval & 0xff00) >> 8);
-	    return;
-	 }
-    }
-    pACB->pActiveDCB = pDCB;
-    if( pDCB->SyncMode & EN_TAG_QUEUEING )
-    {
-	pSRB = pACB->pTmpSRB; /* ?? */
-	pDCB->pActiveSRB = pSRB;
-    }
-    else
-    {
-	pSRB = pDCB->pActiveSRB;
-	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
-	{
-	    pSRB= pACB->pTmpSRB;
-	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
-	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
-		    wval & 0xff, (wval & 0xff00) >> 8);
-	    pDCB->pActiveSRB = pSRB;
-	    dc390_EnableMsgOut_Abort ( pACB, pSRB );
+	bval = DC390_read8(ScsiFifo);	/* get ID */
+	DEBUG0(printk("Dev %02x,", bval);
+	    )
+	    bval ^= 1 << pACB->pScsiHost->this_id;	/* Mask AdapterID */
+	wval = 0;
+	while (bval >>= 1)
+		wval++;
+	wval |= ((USHORT) DC390_read8(ScsiFifo) & 7) << 8;	/* get LUN */
+	DEBUG0(printk("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);
+	    )
+	    pDCB = pACB->pLinkDCB;
+	while (wval != *((PUSHORT) & pDCB->UnitSCSIID)) {
+		pDCB = pDCB->pNextDCB;
+		if (pDCB == pACB->pLinkDCB) {
+			printk(KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n",
+			       wval & 0xff, (wval & 0xff00) >> 8);
+			return;
+		}
 	}
-	else
-	{
-	    if( pDCB->DCBFlag & ABORT_DEV_ )
-	    {
-		pSRB->SRBState = SRB_ABORT_SENT;
-		printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
-			wval & 0xff, (wval & 0xff00) >> 8);
-		dc390_EnableMsgOut_Abort( pACB, pSRB );
-	    }
-	    else
-		pSRB->SRBState = SRB_DATA_XFER;
+	pACB->pActiveDCB = pDCB;
+	if (pDCB->SyncMode & EN_TAG_QUEUEING) {
+		pSRB = pACB->pTmpSRB;	/* ?? */
+		pDCB->pActiveSRB = pSRB;
+	} else {
+		pSRB = pDCB->pActiveSRB;
+		if (!pSRB || !(pSRB->SRBState & SRB_DISCONNECT)) {
+			pSRB = pACB->pTmpSRB;
+			pSRB->SRBState = SRB_UNEXPECT_RESEL;
+			printk(KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
+			       wval & 0xff, (wval & 0xff00) >> 8);
+			pDCB->pActiveSRB = pSRB;
+			dc390_EnableMsgOut_Abort(pACB, pSRB);
+		} else {
+			if (pDCB->DCBFlag & ABORT_DEV_) {
+				pSRB->SRBState = SRB_ABORT_SENT;
+				printk(KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
+				       wval & 0xff, (wval & 0xff00) >> 8);
+				dc390_EnableMsgOut_Abort(pACB, pSRB);
+			} else
+				pSRB->SRBState = SRB_DATA_XFER;
+		}
 	}
-    }
 
-    DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
-    pSRB->ScsiPhase = SCSI_NOP0;
-    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
-    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
-    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
-    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
-    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
-    DC390_write8 (CtrlReg4, pDCB->CtrlR4);	/* ; Glitch eater */
-    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);	/* ;to release the /ACK signal */
+	DEBUG1(printk(KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);
+	    )
+	    pSRB->ScsiPhase = SCSI_NOP0;
+	DC390_write8(Scsi_Dest_ID, pDCB->UnitSCSIID);
+	DC390_write8(Sync_Period, pDCB->SyncPeriod);
+	DC390_write8(Sync_Offset, pDCB->SyncOffset);
+	DC390_write8(CtrlReg1, pDCB->CtrlR1);
+	DC390_write8(CtrlReg3, pDCB->CtrlR3);
+	DC390_write8(CtrlReg4, pDCB->CtrlR4);	/* ; Glitch eater */
+	DC390_write8(ScsiCmd, MSG_ACCEPTED_CMD);	/* ;to release the /ACK signal */
 }
 
 
-static void 
-dc390_remove_dev (PACB pACB, PDCB pDCB)
-{
-   PDCB pPrevDCB = pACB->pLinkDCB;
-
-   pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN);
-   if (pDCB->GoingSRBCnt > 1)
-     {
-	DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
-		pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);)
-	return;
-     };
-   
-   if (pDCB == pACB->pLinkDCB) 
-     {
-	if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0;
-	pACB->pLinkDCB = pDCB->pNextDCB;
-	pACB->pLastDCB->pNextDCB = pDCB->pNextDCB;
-     }
-   else
-     {
-	while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB;
-	pPrevDCB->pNextDCB = pDCB->pNextDCB;
-	if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB;
-     }
-
-   DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\
-	   pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
-   kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
-   pACB->DCBCnt--;
-   /* pACB->DeviceCnt--; */
+static void dc390_remove_dev(PACB pACB, PDCB pDCB)
+{
+	PDCB pPrevDCB = pACB->pLinkDCB;
+
+	pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN);
+	if (pDCB->GoingSRBCnt > 1) {
+		DCBDEBUG(printk(KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n", \
+				pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int) pDCB, pDCB->GoingSRBCnt);
+		    )
+		    return;
+	};
+
+	if (pDCB == pACB->pLinkDCB) {
+		if (pDCB->pNextDCB == pDCB)
+			pDCB->pNextDCB = 0;
+		pACB->pLinkDCB = pDCB->pNextDCB;
+		pACB->pLastDCB->pNextDCB = pDCB->pNextDCB;
+	} else {
+		while (pPrevDCB->pNextDCB != pDCB)
+			pPrevDCB = pPrevDCB->pNextDCB;
+		pPrevDCB->pNextDCB = pDCB->pNextDCB;
+		if (pDCB == pACB->pLastDCB)
+			pACB->pLastDCB = pPrevDCB;
+	}
+
+	DCBDEBUG(printk(KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n", \
+			pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int) pDCB);
+	    )
+	    kfree(pDCB);
+	if (pDCB == pACB->pActiveDCB)
+		pACB->pActiveDCB = 0;
+	pACB->DCBCnt--;
+	/* pACB->DeviceCnt--; */
 };
 
 
 static UCHAR __inline__
-dc390_tagq_blacklist (char* name)
+ dc390_tagq_blacklist(char *name)
 {
-   UCHAR i;
-   for(i=0; i<BADDEVCNT; i++)
-     if (memcmp (name, dc390_baddevname1[i], 28) == 0)
-	return 1;
-   return 0;
+	UCHAR i;
+	for (i = 0; i < BADDEVCNT; i++)
+		if (memcmp(name, dc390_baddevname1[i], 28) == 0)
+			return 1;
+	return 0;
 };
-   
 
-static void 
-dc390_disc_tagq_set (PDCB pDCB, PSCSI_INQDATA ptr)
+
+static void dc390_disc_tagq_set(PDCB pDCB, PSCSI_INQDATA ptr)
 {
-   /* Check for SCSI format (ANSI and Response data format) */
-   if ( (ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 )
-   {
-	if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
-	    (pDCB->DevMode & TAG_QUEUEING_) &&
-	    /* ((pDCB->DevType == TYPE_DISK) 
-		|| (pDCB->DevType == TYPE_MOD)) &&*/
-	    !dc390_tagq_blacklist (((char*)ptr)+8) )
-	  {
-	     pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
-	     pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */;
-	     pDCB->TagMask = 0;
-	  }
-	else
-	  {
-	     /* Do we really need to check for DevType here ? */
-	     if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/
-		 /* && ((pDCB->DevType == TYPE_DISK) 
-		     || (pDCB->DevType == TYPE_MOD))*/ )
-		pDCB->SyncMode |= EN_ATN_STOP;
-	     else
-	       //pDCB->SyncMode &= ~EN_ATN_STOP;
-	       pDCB->SyncMode &= ~0;
-	  }
-     }
+	/* Check for SCSI format (ANSI and Response data format) */
+	if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) {
+		if ((ptr->Flags & SCSI_INQ_CMDQUEUE) &&
+		    (pDCB->DevMode & TAG_QUEUEING_) &&
+		/* ((pDCB->DevType == TYPE_DISK) 
+		   || (pDCB->DevType == TYPE_MOD)) && */
+		    !dc390_tagq_blacklist(((char *) ptr) + 8)) {
+			pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
+			pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */ ;
+			pDCB->TagMask = 0;
+		} else {
+			/* Do we really need to check for DevType here ? */
+			if (0	/*(pDCB->DevMode & EN_DISCONNECT_) */
+			/* && ((pDCB->DevType == TYPE_DISK) 
+			   || (pDCB->DevType == TYPE_MOD)) */ )
+				pDCB->SyncMode |= EN_ATN_STOP;
+			else
+				//pDCB->SyncMode &= ~EN_ATN_STOP;
+				pDCB->SyncMode &= ~0;
+		}
+	}
 };
 
 
-static void 
-dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr)
+static void dc390_add_dev(PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr)
 {
-   UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE;
-   pDCB->DevType = bval1;
-   /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
-	dc390_disc_tagq_set (pDCB, ptr);
+	UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE;
+	pDCB->DevType = bval1;
+	/* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
+	dc390_disc_tagq_set(pDCB, ptr);
 };
 
 
-void
-dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
+void dc390_SRBdone(PACB pACB, PDCB pDCB, PSRB pSRB)
 {
-    PSRB   psrb;
-    UCHAR  bval, status, i;
-    PSCSICMD pcmd;
-    PSCSI_INQDATA  ptr;
-    PSGL   ptr2;
-    ULONG  swlval;
-
-    pcmd = pSRB->pcmd;
-    status = pSRB->TargetStatus;
-    DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
-		pSRB, pcmd->pid);)
-    if(pSRB->SRBFlag & AUTO_REQSENSE)
-    {	/* Last command was a Request Sense */
-	pSRB->SRBFlag &= ~AUTO_REQSENSE;
-	pSRB->AdaptStatus = 0;
-	pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+	PSRB psrb;
+	UCHAR bval, status, i;
+	PSCSICMD pcmd;
+	PSCSI_INQDATA ptr;
+	PSGL ptr2;
+	ULONG swlval;
+
+	pcmd = pSRB->pcmd;
+	status = pSRB->TargetStatus;
+	DEBUG0(printk(" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result, \
+		      pSRB, pcmd->pid);
+	    )
+	    if (pSRB->SRBFlag & AUTO_REQSENSE) {	/* Last command was a Request Sense */
+		pSRB->SRBFlag &= ~AUTO_REQSENSE;
+		pSRB->AdaptStatus = 0;
+		pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
 #ifdef DC390_REMOVABLEDEBUG
-	switch (pcmd->sense_buffer[2] & 0x0f)
-	{	    
-	 case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				 pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
-				 status, pACB->scan_devices); break;
-	 case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
-				      status, pACB->scan_devices); break;
-	 case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
-				       status, pACB->scan_devices); break;
-	 case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				    pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
-				    status, pACB->scan_devices); break;
-	 case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
-				      status, pACB->scan_devices); break;
-	}
+		switch (pcmd->sense_buffer[2] & 0x0f) {
+		case NOT_READY:
+			printk(KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+			       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+			       status, pACB->scan_devices);
+			break;
+		case UNIT_ATTENTION:
+			printk(KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+			       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+			       status, pACB->scan_devices);
+			break;
+		case ILLEGAL_REQUEST:
+			printk(KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+			       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+			       status, pACB->scan_devices);
+			break;
+		case MEDIUM_ERROR:
+			printk(KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+			       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+			       status, pACB->scan_devices);
+			break;
+		case HARDWARE_ERROR:
+			printk(KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
+			       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+			       status, pACB->scan_devices);
+			break;
+		}
 #endif
-	//pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status;
-	if(status == SCSI_STAT_CHECKCOND)
-	{
-	    pcmd->result = DID_BAD_TARGET << 16;
-	    goto ckc_e;
-	}
-	if(pSRB->RetryCnt == 0)
-	{
-	    (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0];
-	    pSRB->TotalXferredLen = pSRB->Segment1[1];
-	    if( (pSRB->TotalXferredLen) &&
-		(pSRB->TotalXferredLen >= pcmd->underflow) )
-		pcmd->result |= (DID_OK << 16);
-	    else
-		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
-				SCSI_STAT_CHECKCOND;
-	    REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
-		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
-	    goto ckc_e;
-	}
-	else /* Retry */
-	{
-	    pSRB->RetryCnt--;
-	    pSRB->AdaptStatus = 0;
-	    pSRB->TargetStatus = 0;
-	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
-	    *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
-	    /* Don't retry on TEST_UNIT_READY */
-	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */)
-	    {
-		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) 
-			    | SCSI_STAT_CHECKCOND;
-		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
-		       (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
-		goto ckc_e;
-	    }
-	    pcmd->result |= (DRIVER_SENSE << 24);
-	    pSRB->SGcount	 = (UCHAR) pSRB->Segment1[0];
-	    pSRB->ScsiCmdLen	 = (UCHAR) (pSRB->Segment1[0] >> 8);
-	    pSRB->SGIndex = 0;
-	    pSRB->TotalXferredLen = 0;
-	    pSRB->SGToBeXferLen = 0;
-	    if( pcmd->use_sg )
-		pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
-	    else if( pcmd->request_buffer )
-	    {
-		pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
-		pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
-		pSRB->Segmentx.length = pcmd->request_bufflen;
-	    }
-	    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
-		dc390_RewaitSRB( pDCB, pSRB );
-	    return;
-	}
-    }
-    if( status )
-    {
-	if( status == SCSI_STAT_CHECKCOND)
-	{
-	    REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\
-		    pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
-	    if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
-	    {
-		bval = pSRB->SGcount;
-		swlval = 0;
-		ptr2 = pSRB->pSegmentList;
-		for( i=pSRB->SGIndex; i < bval; i++)
-		{
-		    swlval += ptr2->length;
-		    ptr2++;
-		}
-		REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n",\
-			(UINT) pSRB->TotalXferredLen, (UINT) swlval);)
-	    }
-	    dc390_RequestSense( pACB, pDCB, pSRB );
-	    return;
-	}
-	else if( status == SCSI_STAT_QUEUEFULL )
-	{
-	    bval = (UCHAR) pDCB->GoingSRBCnt;
-	    bval--;
-	    pDCB->MaxCommand = bval;
-	    dc390_RewaitSRB( pDCB, pSRB );
-	    pSRB->AdaptStatus = 0;
-	    pSRB->TargetStatus = 0;
-	    return;
-	}
-	else if(status == SCSI_STAT_SEL_TIMEOUT)
-	{
-	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
-	    pSRB->TargetStatus = 0;
-	    pcmd->result = DID_BAD_TARGET << 16;
-	    /* Devices are removed below ... */
-	}
-	else if (status == SCSI_STAT_BUSY && 
-		 (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) &&
-		 pACB->scan_devices)
-	{
-	    pSRB->AdaptStatus = 0;
-	    pSRB->TargetStatus = status;
-	    pcmd->result = (ULONG) (pSRB->EndMessage << 8)
-				/* | (ULONG) status */;
-	}
-	else
-	{   /* Another error */
-	    pSRB->AdaptStatus = 0;
-	    if( pSRB->RetryCnt )
-	    {	/* Retry */
-		pSRB->RetryCnt--;
-		pSRB->TargetStatus = 0;
-		pSRB->SGIndex = 0;
-		pSRB->TotalXferredLen = 0;
-		pSRB->SGToBeXferLen = 0;
-		if( pcmd->use_sg )
-		    pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
-		else if( pcmd->request_buffer )
-		{
-		    pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
-		    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
-		    pSRB->Segmentx.length = pcmd->request_bufflen;
+		//pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status;
+		if (status == SCSI_STAT_CHECKCOND) {
+			pcmd->result = DID_BAD_TARGET << 16;
+			goto ckc_e;
+		}
+		if (pSRB->RetryCnt == 0) {
+			(ULONG) (pSRB->CmdBlock[0]) = pSRB->Segment0[0];
+			pSRB->TotalXferredLen = pSRB->Segment1[1];
+			if ((pSRB->TotalXferredLen) &&
+			    (pSRB->TotalXferredLen >= pcmd->underflow))
+				pcmd->result |= (DID_OK << 16);
+			else
+				pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
+				    SCSI_STAT_CHECKCOND;
+			REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n", pSRB->CmdBlock[0], \
+					      (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
+			    )
+			    goto ckc_e;
+		} else {	/* Retry */
+			pSRB->RetryCnt--;
+			pSRB->AdaptStatus = 0;
+			pSRB->TargetStatus = 0;
+			*((PULONG) & (pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+			*((PULONG) & (pSRB->CmdBlock[4])) = pSRB->Segment0[1];
+			/* Don't retry on TEST_UNIT_READY */
+			if (pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */ ) {
+				pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16)
+				    | SCSI_STAT_CHECKCOND;
+				REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n", pSRB->CmdBlock[0], \
+						      (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);
+				    )
+				    goto ckc_e;
+			}
+			pcmd->result |= (DRIVER_SENSE << 24);
+			pSRB->SGcount = (UCHAR) pSRB->Segment1[0];
+			pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8);
+			pSRB->SGIndex = 0;
+			pSRB->TotalXferredLen = 0;
+			pSRB->SGToBeXferLen = 0;
+			if (pcmd->use_sg)
+				pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+			else if (pcmd->request_buffer) {
+				pSRB->pSegmentList = (PSGL) & pSRB->Segmentx;
+				pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+				pSRB->Segmentx.length = pcmd->request_bufflen;
+			}
+			if (dc390_StartSCSI(pACB, pDCB, pSRB))
+				dc390_RewaitSRB(pDCB, pSRB);
+			return;
 		}
-		if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
-		    dc390_RewaitSRB( pDCB, pSRB );
-		return;
-	    }
-	    else
-	    {	/* Report error */
-		pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
-			       (ULONG) status;
-	    }
-	}
-    }
-    else
-    {	/*  Target status == 0 */
-	status = pSRB->AdaptStatus;
-	if(status & H_OVER_UNDER_RUN)
-	{
-	    pSRB->TargetStatus = 0;
-	    pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
 	}
-	else if( pSRB->SRBStatus & PARITY_ERROR)
-	{
-	    pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+	if (status) {
+		if (status == SCSI_STAT_CHECKCOND) {
+			REMOVABLEDEBUG(printk(KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n", \
+					      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+			    )
+			    if ((pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen)) {
+				bval = pSRB->SGcount;
+				swlval = 0;
+				ptr2 = pSRB->pSegmentList;
+				for (i = pSRB->SGIndex; i < bval; i++) {
+					swlval += ptr2->length;
+					ptr2++;
+				}
+				REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n", \
+						      (UINT) pSRB->TotalXferredLen, (UINT) swlval);
+				    )
+			}
+			dc390_RequestSense(pACB, pDCB, pSRB);
+			return;
+		} else if (status == SCSI_STAT_QUEUEFULL) {
+			bval = (UCHAR) pDCB->GoingSRBCnt;
+			bval--;
+			pDCB->MaxCommand = bval;
+			dc390_RewaitSRB(pDCB, pSRB);
+			pSRB->AdaptStatus = 0;
+			pSRB->TargetStatus = 0;
+			return;
+		} else if (status == SCSI_STAT_SEL_TIMEOUT) {
+			pSRB->AdaptStatus = H_SEL_TIMEOUT;
+			pSRB->TargetStatus = 0;
+			pcmd->result = DID_BAD_TARGET << 16;
+			/* Devices are removed below ... */
+		} else if (status == SCSI_STAT_BUSY &&
+			   (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) &&
+			   pACB->scan_devices) {
+			pSRB->AdaptStatus = 0;
+			pSRB->TargetStatus = status;
+			pcmd->result = (ULONG) (pSRB->EndMessage << 8)
+			/* | (ULONG) status */ ;
+		} else {	/* Another error */
+			pSRB->AdaptStatus = 0;
+			if (pSRB->RetryCnt) {	/* Retry */
+				pSRB->RetryCnt--;
+				pSRB->TargetStatus = 0;
+				pSRB->SGIndex = 0;
+				pSRB->TotalXferredLen = 0;
+				pSRB->SGToBeXferLen = 0;
+				if (pcmd->use_sg)
+					pSRB->pSegmentList = (PSGL) pcmd->request_buffer;
+				else if (pcmd->request_buffer) {
+					pSRB->pSegmentList = (PSGL) & pSRB->Segmentx;
+					pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
+					pSRB->Segmentx.length = pcmd->request_bufflen;
+				}
+				if (dc390_StartSCSI(pACB, pDCB, pSRB))
+					dc390_RewaitSRB(pDCB, pSRB);
+				return;
+			} else {	/* Report error */
+				pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
+				    (ULONG) status;
+			}
+		}
+	} else {		/*  Target status == 0 */
+		status = pSRB->AdaptStatus;
+		if (status & H_OVER_UNDER_RUN) {
+			pSRB->TargetStatus = 0;
+			pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
+		} else if (pSRB->SRBStatus & PARITY_ERROR) {
+			pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+		} else {	/* No error */
+			pSRB->AdaptStatus = 0;
+			pSRB->TargetStatus = 0;
+			pcmd->result |= (DID_OK << 16);
+		}
 	}
-	else		       /* No error */
-	{
-	    pSRB->AdaptStatus = 0;
-	    pSRB->TargetStatus = 0;
-	    pcmd->result |= (DID_OK << 16);
-	}
-    }
-
-ckc_e:
-    if( pACB->scan_devices )
-    {
-	if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
-	{
+
+      ckc_e:
+	if (pACB->scan_devices) {
+		if (pSRB->CmdBlock[0] == TEST_UNIT_READY) {
 #ifdef DC390_DEBUG0
-	    printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result);
-	    if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n",
-				   pcmd->sense_buffer[0], pcmd->sense_buffer[1],
-				   pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
-	    else printk ("\n");
+			printk(KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result);
+			if (pcmd->result & DRIVER_SENSE << 24)
+				printk(" (sense: %02x %02x %02x %02x)\n",
+				       pcmd->sense_buffer[0], pcmd->sense_buffer[1],
+				       pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
+			else
+				printk("\n");
 #endif
-	    if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) ||
-	       ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
-		(pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16)
-	    {
-	       /* device not present: remove */ 
-	       dc390_remove_dev (pACB, pDCB);
-	       
-	       if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
-		  ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) )
-		 pACB->scan_devices = 0;
-	    }
-	    else
-	    {
-	        /* device present: add */
-		if( (pcmd->target == pACB->pScsiHost->max_id - 1) && 
-		    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
-		    pACB->scan_devices = END_SCAN ;
-	        /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */
-	    }
-	}
-    }
-   
-   if( pSRB->CmdBlock[0] == INQUIRY && 
-      (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) )
-     {
-	ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
-	if( pcmd->use_sg )
-	  ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
-	if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV)
-	  {
-	     /* device not present: remove */
-	     dc390_remove_dev (pACB, pDCB);
-	  }
-	else
-	  {
-	     /* device found: add */ 
-	     dc390_add_dev (pACB, pDCB, ptr);
-	     if (pACB->scan_devices) pACB->DeviceCnt++;
-	  }
-	if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
-	    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
-	  pACB->scan_devices = 0;
-     };
+			if ((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) ||
+			    ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
+			     (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) {
+				/* device not present: remove */
+				dc390_remove_dev(pACB, pDCB);
+
+				if ((pcmd->target == pACB->pScsiHost->max_id - 1) &&
+				    ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)))
+					pACB->scan_devices = 0;
+			} else {
+				/* device present: add */
+				if ((pcmd->target == pACB->pScsiHost->max_id - 1) &&
+				    (pcmd->lun == pACB->pScsiHost->max_lun - 1))
+					pACB->scan_devices = END_SCAN;
+				/* pACB->DeviceCnt++; *//* Dev is added on INQUIRY */
+			}
+		}
+	}
+	if (pSRB->CmdBlock[0] == INQUIRY &&
+	    (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND)) {
+		ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+		if (pcmd->use_sg)
+			ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+		if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) {
+			/* device not present: remove */
+			dc390_remove_dev(pACB, pDCB);
+		} else {
+			/* device found: add */
+			dc390_add_dev(pACB, pDCB, ptr);
+			if (pACB->scan_devices)
+				pACB->DeviceCnt++;
+		}
+		if ((pcmd->target == pACB->pScsiHost->max_id - 1) &&
+		    (pcmd->lun == pACB->pScsiHost->max_lun - 1))
+			pACB->scan_devices = 0;
+	};
 /*  dc390_ReleaseSRB( pDCB, pSRB ); */
 
-    if(pSRB == pDCB->pGoingSRB )
-    {
-	pDCB->pGoingSRB = pSRB->pNextSRB;
-    }
-    else
-    {
-	psrb = pDCB->pGoingSRB;
-	while( psrb->pNextSRB != pSRB )
-	    psrb = psrb->pNextSRB;
-	psrb->pNextSRB = pSRB->pNextSRB;
-	if( pSRB == pDCB->pGoingLast )
-	    pDCB->pGoingLast = psrb;
-    }
-    pSRB->pNextSRB = pACB->pFreeSRB;
-    pACB->pFreeSRB = pSRB;
-    pDCB->GoingSRBCnt--;
-
-    dc390_DoWaitingSRB( pACB );
-
-    DC390_UNLOCK_ACB_NI;
-    pcmd->scsi_done( pcmd );
-    DC390_LOCK_ACB_NI;
-
-    if( pDCB->QIORBCnt )
-	dc390_DoNextCmd( pACB, pDCB );
-    return;
+	if (pSRB == pDCB->pGoingSRB) {
+		pDCB->pGoingSRB = pSRB->pNextSRB;
+	} else {
+		psrb = pDCB->pGoingSRB;
+		while (psrb->pNextSRB != pSRB)
+			psrb = psrb->pNextSRB;
+		psrb->pNextSRB = pSRB->pNextSRB;
+		if (pSRB == pDCB->pGoingLast)
+			pDCB->pGoingLast = psrb;
+	}
+	pSRB->pNextSRB = pACB->pFreeSRB;
+	pACB->pFreeSRB = pSRB;
+	pDCB->GoingSRBCnt--;
+
+	dc390_DoWaitingSRB(pACB);
+
+	DC390_UNLOCK_ACB_NI;
+	pcmd->scsi_done(pcmd);
+	DC390_LOCK_ACB_NI;
+
+	if (pDCB->QIORBCnt)
+		dc390_DoNextCmd(pACB, pDCB);
+	return;
 }
 
 
 /* Remove all SRBs and tell midlevel code DID_RESET */
-void
-dc390_DoingSRB_Done( PACB pACB )
+void dc390_DoingSRB_Done(PACB pACB)
 {
-    PDCB   pDCB, pdcb;
-    PSRB   psrb, psrb2;
-    UCHAR  i;
-    PSCSICMD pcmd;
-
-    pDCB = pACB->pLinkDCB;
-    pdcb = pDCB;
-    if (! pdcb) return;
-    do
-    {
-	psrb = pdcb->pGoingSRB;
-	for( i=0; i<pdcb->GoingSRBCnt; i++)
-	{
-	    psrb2 = psrb->pNextSRB;
-	    pcmd = psrb->pcmd;
-	    pcmd->result = DID_RESET << 16;
-
-/*	    ReleaseSRB( pDCB, pSRB ); */
-
-	    psrb->pNextSRB = pACB->pFreeSRB;
-	    pACB->pFreeSRB = psrb;
-
-	    DC390_UNLOCK_ACB_NI;
-	    pcmd->scsi_done( pcmd );
-	    DC390_LOCK_ACB_NI;
-	    psrb  = psrb2;
-	}
-	pdcb->GoingSRBCnt = 0;;
-	pdcb->pGoingSRB = NULL;
-	pdcb->TagMask = 0;
-	pdcb = pdcb->pNextDCB;
-    } while( pdcb != pDCB );
+	PDCB pDCB, pdcb;
+	PSRB psrb, psrb2;
+	UCHAR i;
+	PSCSICMD pcmd;
+
+	pDCB = pACB->pLinkDCB;
+	pdcb = pDCB;
+	if (!pdcb)
+		return;
+	do {
+		psrb = pdcb->pGoingSRB;
+		for (i = 0; i < pdcb->GoingSRBCnt; i++) {
+			psrb2 = psrb->pNextSRB;
+			pcmd = psrb->pcmd;
+			pcmd->result = DID_RESET << 16;
+
+/*          ReleaseSRB( pDCB, pSRB ); */
+
+			psrb->pNextSRB = pACB->pFreeSRB;
+			pACB->pFreeSRB = psrb;
+
+			DC390_UNLOCK_ACB_NI;
+			pcmd->scsi_done(pcmd);
+			DC390_LOCK_ACB_NI;
+			psrb = psrb2;
+		}
+		pdcb->GoingSRBCnt = 0;;
+		pdcb->pGoingSRB = NULL;
+		pdcb->TagMask = 0;
+		pdcb = pdcb->pNextDCB;
+	} while (pdcb != pDCB);
 }
 
 
-static void
-dc390_ResetSCSIBus( PACB pACB )
+static void dc390_ResetSCSIBus(PACB pACB)
 {
-    pACB->ACBFlag |= RESET_DEV;
+	pACB->ACBFlag |= RESET_DEV;
 
-    DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
-    udelay (250);
-    DC390_write8 (ScsiCmd, NOP_CMD);
+	DC390_write8(ScsiCmd, RST_DEVICE_CMD);
+	udelay(250);
+	DC390_write8(ScsiCmd, NOP_CMD);
 
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-    DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+	DC390_write8(DMA_Cmd, DMA_IDLE_CMD);
+	DC390_write8(ScsiCmd, RST_SCSI_BUS_CMD);
 
-    return;
+	return;
 }
 
-static void
-dc390_ScsiRstDetect( PACB pACB )
+static void dc390_ScsiRstDetect(PACB pACB)
 {
-    printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
-    //DEBUG0(printk(KERN_INFO "RST_DETECT,");)
+	printk("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
+	//DEBUG0(printk(KERN_INFO "RST_DETECT,");)
 
-    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-    /* Unlock before ? */
-    /* delay a second */
-    { unsigned int msec = 1*1000; while (--msec) udelay(1000); }
-    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-
-    if( pACB->ACBFlag & RESET_DEV )
-	pACB->ACBFlag |= RESET_DONE;
-    else
-    {
-	pACB->ACBFlag |= RESET_DETECT;
-
-	dc390_ResetDevParam( pACB );
-/*	dc390_DoingSRB_Done( pACB ); ???? */
-	dc390_RecoverSRB( pACB );
-	pACB->pActiveDCB = NULL;
-	pACB->ACBFlag = 0;
-	dc390_DoWaitingSRB( pACB );
-    }
-    return;
+	DC390_write8(DMA_Cmd, DMA_IDLE_CMD);
+	/* Unlock before ? */
+	/* delay a second */
+	{
+		unsigned int msec = 1 * 1000;
+		while (--msec)
+			udelay(1000);
+	}
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+
+	if (pACB->ACBFlag & RESET_DEV)
+		pACB->ACBFlag |= RESET_DONE;
+	else {
+		pACB->ACBFlag |= RESET_DETECT;
+
+		dc390_ResetDevParam(pACB);
+/*      dc390_DoingSRB_Done( pACB ); ???? */
+		dc390_RecoverSRB(pACB);
+		pACB->pActiveDCB = NULL;
+		pACB->ACBFlag = 0;
+		dc390_DoWaitingSRB(pACB);
+	}
+	return;
 }
 
 
 static void __inline__
-dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
+ dc390_RequestSense(PACB pACB, PDCB pDCB, PSRB pSRB)
 {
-    PSCSICMD  pcmd;
+	PSCSICMD pcmd;
 
-    REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\
-	    pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+	REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n", \
+		 pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+	    )
+	    pSRB->SRBFlag |= AUTO_REQSENSE;
+	pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
+	pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
+	pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
+	pSRB->Segment1[1] = pSRB->TotalXferredLen;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = 0;	/* SCSI_STAT_CHECKCOND; */
+
+	pcmd = pSRB->pcmd;
 
-    pSRB->SRBFlag |= AUTO_REQSENSE;
-    pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
-    pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
-    pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
-    pSRB->Segment1[1] = pSRB->TotalXferredLen;
-    pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */
-
-    pcmd = pSRB->pcmd;
-
-    pSRB->Segmentx.address = (PUCHAR) &(pcmd->sense_buffer);
-    pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
-    pSRB->pSegmentList = &pSRB->Segmentx;
-    pSRB->SGcount = 1;
-    pSRB->SGIndex = 0;
-
-    pSRB->CmdBlock[0] = REQUEST_SENSE;
-    pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
-    (USHORT) pSRB->CmdBlock[2] = 0;
-    (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
-    pSRB->ScsiCmdLen = 6;
-
-    pSRB->TotalXferredLen = 0;
-    pSRB->SGToBeXferLen = 0;
-    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
-	dc390_RewaitSRB( pDCB, pSRB );
+	pSRB->Segmentx.address = (PUCHAR) & (pcmd->sense_buffer);
+	pSRB->Segmentx.length = sizeof(pcmd->sense_buffer);
+	pSRB->pSegmentList = &pSRB->Segmentx;
+	pSRB->SGcount = 1;
+	pSRB->SGIndex = 0;
+
+	pSRB->CmdBlock[0] = REQUEST_SENSE;
+	pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
+	(USHORT) pSRB->CmdBlock[2] = 0;
+	(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
+	pSRB->ScsiCmdLen = 6;
+
+	pSRB->TotalXferredLen = 0;
+	pSRB->SGToBeXferLen = 0;
+	if (dc390_StartSCSI(pACB, pDCB, pSRB))
+		dc390_RewaitSRB(pDCB, pSRB);
 }
 
 
 
 static void __inline__
-dc390_InvalidCmd( PACB pACB )
+ dc390_InvalidCmd(PACB pACB)
 {
-    if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) )
-	DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+	if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ + SRB_MSGOUT))
+		DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
 }
-
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.3.16/linux/drivers/scsi/sd.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/scsi/sd.c	Sat Sep  4 10:48:46 1999
@@ -18,7 +18,7 @@
  *       Modified by Jirka Hanika geo@ff.cuni.cz to support more
  *       scsi disks using eight major numbers.
  */
- 
+
 #include <linux/module.h>
 #ifdef MODULE
 /*
@@ -29,7 +29,7 @@
 #define MODULE_FLAG 1
 #else
 #define MODULE_FLAG scsi_loadable_module_flag
-#endif /* MODULE */
+#endif				/* MODULE */
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -57,9 +57,9 @@
 /*
  *  static const char RCSid[] = "$Header:";
  */
- 
+
 #define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
- 
+
 #define SCSI_DISKS_PER_MAJOR	16
 #define SD_MAJOR_NUMBER(i)	SD_MAJOR((i) >> 8)
 #define SD_MINOR_NUMBER(i)	((i) & 255)
@@ -80,12 +80,12 @@
 #define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \
 				SC->device->type != TYPE_MOD)
 
-struct hd_struct * sd;
+struct hd_struct *sd;
 
-Scsi_Disk * rscsi_disks = NULL;
-static int * sd_sizes;
-static int * sd_blocksizes;
-static int * sd_hardsizes;              /* Hardware sector size */
+Scsi_Disk *rscsi_disks = NULL;
+static int *sd_sizes;
+static int *sd_blocksizes;
+static int *sd_hardsizes;	/* Hardware sector size */
 
 extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
@@ -94,7 +94,7 @@
 
 static int sd_init_onedisk(int);
 
-static void requeue_sd_request (Scsi_Cmnd * SCpnt);
+static void requeue_sd_request(Scsi_Cmnd * SCpnt);
 
 static int sd_init(void);
 static void sd_finish(void);
@@ -102,175 +102,171 @@
 static int sd_detect(Scsi_Device *);
 static void sd_detach(Scsi_Device *);
 
-static void sd_devname(unsigned int disknum, char * buffer)
+static void sd_devname(unsigned int disknum, char *buffer)
 {
-    if( disknum < 26 )
-        sprintf(buffer, "sd%c", 'a' + disknum);
-    else {
-        unsigned int min1;
-        unsigned int min2;
-        /*
-         * For larger numbers of disks, we need to go to a new
-         * naming scheme.
-         */
-        min1 = disknum / 26;
-        min2 = disknum % 26;
-        sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
-    }
+	if (disknum < 26)
+		sprintf(buffer, "sd%c", 'a' + disknum);
+	else {
+		unsigned int min1;
+		unsigned int min2;
+		/*
+		 * For larger numbers of disks, we need to go to a new
+		 * naming scheme.
+		 */
+		min1 = disknum / 26;
+		min2 = disknum % 26;
+		sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);
+	}
 }
 
 struct Scsi_Device_Template sd_template =
-{ NULL, "disk", "sd", NULL, TYPE_DISK,
-      SCSI_DISK0_MAJOR, 0, 0, 0, 1,
-      sd_detect, sd_init,
-      sd_finish, sd_attach, sd_detach
+{NULL, "disk", "sd", NULL, TYPE_DISK,
+ SCSI_DISK0_MAJOR, 0, 0, 0, 1,
+ sd_detect, sd_init,
+ sd_finish, sd_attach, sd_detach
 };
 
-static int sd_open(struct inode * inode, struct file * filp)
+static int sd_open(struct inode *inode, struct file *filp)
 {
-    int target;
-    target =  DEVICE_NR(inode->i_rdev);
+	int target;
+	target = DEVICE_NR(inode->i_rdev);
 
-    SCSI_LOG_HLQUEUE(1,printk("target=%d, max=%d\n", target, sd_template.dev_max));
+	SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max));
 
-    if(target >= sd_template.dev_max || !rscsi_disks[target].device)
-	return -ENXIO;   /* No such device */
-
-    /*
-     * If the device is in error recovery, wait until it is done.
-     * If the device is offline, then disallow any access to it.
-     */
-    if( !scsi_block_when_processing_errors(rscsi_disks[target].device) )
-      {
-        return -ENXIO;
-      }
-
-    /*
-     * Make sure that only one process can do a check_change_disk at one time.
-     * This is also used to lock out further access when the partition table
-     * is being re-read.
-     */
-
-    while (rscsi_disks[target].device->busy)
-        barrier();
-    if(rscsi_disks[target].device->removable) {
-	check_disk_change(inode->i_rdev);
+	if (target >= sd_template.dev_max || !rscsi_disks[target].device)
+		return -ENXIO;	/* No such device */
 
 	/*
-	 * If the drive is empty, just let the open fail.
+	 * If the device is in error recovery, wait until it is done.
+	 * If the device is offline, then disallow any access to it.
 	 */
-	if ( !rscsi_disks[target].ready )
-	    return -ENXIO;
+	if (!scsi_block_when_processing_errors(rscsi_disks[target].device)) {
+		return -ENXIO;
+	}
+	/*
+	 * Make sure that only one process can do a check_change_disk at one time.
+	 * This is also used to lock out further access when the partition table
+	 * is being re-read.
+	 */
+
+	while (rscsi_disks[target].device->busy)
+		barrier();
+	if (rscsi_disks[target].device->removable) {
+		check_disk_change(inode->i_rdev);
 
+		/*
+		 * If the drive is empty, just let the open fail.
+		 */
+		if (!rscsi_disks[target].ready)
+			return -ENXIO;
+
+		/*
+		 * Similarly, if the device has the write protect tab set,
+		 * have the open fail if the user expects to be able to write
+		 * to the thing.
+		 */
+		if ((rscsi_disks[target].write_prot) && (filp->f_mode & 2))
+			return -EROFS;
+	}
+	/*
+	 * It is possible that the disk changing stuff resulted in the device being taken
+	 * offline.  If this is the case, report this to the user, and don't pretend that
+	 * the open actually succeeded.
+	 */
+	if (!rscsi_disks[target].device->online) {
+		return -ENXIO;
+	}
 	/*
-	 * Similarly, if the device has the write protect tab set,
-	 * have the open fail if the user expects to be able to write
-	 * to the thing.
+	 * See if we are requesting a non-existent partition.  Do this
+	 * after checking for disk change.
 	 */
-	if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) )
-	    return -EROFS;
-    }
-
-    /*
-     * It is possible that the disk changing stuff resulted in the device being taken
-     * offline.  If this is the case, report this to the user, and don't pretend that
-     * the open actually succeeded.
-     */
-    if( !rscsi_disks[target].device->online )
-    {
-        return -ENXIO;
-    }
-
-    /*
-     * See if we are requesting a non-existent partition.  Do this
-     * after checking for disk change.
-     */
-    if(sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
-	return -ENXIO;
-
-    if(rscsi_disks[target].device->removable)
-	if(!rscsi_disks[target].device->access_count)
-	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
-
-    rscsi_disks[target].device->access_count++;
-    if (rscsi_disks[target].device->host->hostt->module)
-        __MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
-    if(sd_template.module)
-        __MOD_INC_USE_COUNT(sd_template.module);
-    return 0;
+	if (sd_sizes[SD_PARTITION(inode->i_rdev)] == 0)
+		return -ENXIO;
+
+	if (rscsi_disks[target].device->removable)
+		if (!rscsi_disks[target].device->access_count)
+			sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+
+	rscsi_disks[target].device->access_count++;
+	if (rscsi_disks[target].device->host->hostt->module)
+		__MOD_INC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+	if (sd_template.module)
+		__MOD_INC_USE_COUNT(sd_template.module);
+	return 0;
 }
 
-static int sd_release(struct inode * inode, struct file * file)
+static int sd_release(struct inode *inode, struct file *file)
 {
-    int target;
-    fsync_dev(inode->i_rdev);
-
-    target =  DEVICE_NR(inode->i_rdev);
+	int target;
+	fsync_dev(inode->i_rdev);
 
-    rscsi_disks[target].device->access_count--;
+	target = DEVICE_NR(inode->i_rdev);
 
-    if(rscsi_disks[target].device->removable) {
-	if(!rscsi_disks[target].device->access_count)
-	    sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
-    }
+	rscsi_disks[target].device->access_count--;
 
-    if(rscsi_disks[target].device->host->hostt->module)
-        __MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
-    if(sd_template.module)
-        __MOD_DEC_USE_COUNT(sd_template.module);
-    return 0;
+	if (rscsi_disks[target].device->removable) {
+		if (!rscsi_disks[target].device->access_count)
+			sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+	}
+	if (rscsi_disks[target].device->host->hostt->module)
+		__MOD_DEC_USE_COUNT(rscsi_disks[target].device->host->hostt->module);
+	if (sd_template.module)
+		__MOD_DEC_USE_COUNT(sd_template.module);
+	return 0;
 }
 
 static void sd_geninit(struct gendisk *);
 
-static struct file_operations sd_fops = {
-    NULL,                        /* lseek - default */
-    block_read,                  /* read - general block-dev read */
-    block_write,                 /* write - general block-dev write */
-    NULL,                        /* readdir - bad */
-    NULL,                        /* select */
-    sd_ioctl,                    /* ioctl */
-    NULL,                        /* mmap */
-    sd_open,                     /* open code */
-    NULL,			 /* flush */
-    sd_release,                  /* release */
-    block_fsync,                 /* fsync */
-    NULL,                        /* fasync */
-    check_scsidisk_media_change, /* Disk change */
-    fop_revalidate_scsidisk      /* revalidate */
+static struct file_operations sd_fops =
+{
+	NULL,			/* lseek - default */
+	block_read,		/* read - general block-dev read */
+	block_write,		/* write - general block-dev write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	sd_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	sd_open,		/* open code */
+	NULL,			/* flush */
+	sd_release,		/* release */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	check_scsidisk_media_change,	/* Disk change */
+	fop_revalidate_scsidisk	/* revalidate */
 };
 
 /*
- *	If we need more than one SCSI disk major (i.e. more than
- *	16 SCSI disks), we'll have to kmalloc() more gendisks later.
+ *    If we need more than one SCSI disk major (i.e. more than
+ *      16 SCSI disks), we'll have to kmalloc() more gendisks later.
  */
 
-static struct gendisk sd_gendisk = {
-    SCSI_DISK0_MAJOR,            /* Major number */
-    "sd",                        /* Major name */
-    4,                           /* Bits to shift to get real from partition */
-    1 << 4,                      /* Number of partitions per real */
-    0,                           /* maximum number of real */
-    sd_geninit,                  /* init function */
-    NULL,                        /* hd struct */
-    NULL,                        /* block sizes */
-    0,                           /* number */
-    NULL,                        /* internal */
-    NULL                         /* next */
-}; 
+static struct gendisk sd_gendisk =
+{
+	SCSI_DISK0_MAJOR,	/* Major number */
+	"sd",			/* Major name */
+	4,			/* Bits to shift to get real from partition */
+	1 << 4,			/* Number of partitions per real */
+	0,			/* maximum number of real */
+	sd_geninit,		/* init function */
+	NULL,			/* hd struct */
+	NULL,			/* block sizes */
+	0,			/* number */
+	NULL,			/* internal */
+	NULL			/* next */
+};
 
 static struct gendisk *sd_gendisks = &sd_gendisk;
 
 #define SD_GENDISK(i)    sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
 #define LAST_SD_GENDISK  sd_gendisks[N_USED_SD_MAJORS - 1]
 
-static void sd_geninit (struct gendisk *ignored)
+static void sd_geninit(struct gendisk *ignored)
 {
-    int i;
+	int i;
 
-    for (i = 0; i < sd_template.dev_max; ++i)
-	if(rscsi_disks[i].device)
-	    sd[i << 4].nr_sects = rscsi_disks[i].capacity;
+	for (i = 0; i < sd_template.dev_max; ++i)
+		if (rscsi_disks[i].device)
+			sd[i << 4].nr_sects = rscsi_disks[i].capacity;
 }
 
 /*
@@ -279,1208 +275,1169 @@
  * will take one of several actions based on success or failure.
  */
 
-static void rw_intr (Scsi_Cmnd *SCpnt)
+static void rw_intr(Scsi_Cmnd * SCpnt)
 {
-    int result = SCpnt->result;
-    char nbuff[6];
-    int this_count = SCpnt->bufflen >> 9;
-    int good_sectors = (result == 0 ? this_count : 0);
-    int block_sectors = 1;
-
-    sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff);
-
-    SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
-	   SCpnt->host->host_no, 
-                                 result, 
-                                 SCpnt->sense_buffer[0],
-                                 SCpnt->sense_buffer[2]));
-
-    /*
-      Handle MEDIUM ERRORs that indicate partial success.  Since this is a
-      relatively rare error condition, no care is taken to avoid unnecessary
-      additional work such as memcpy's that could be avoided.
-    */
-
-    if (driver_byte(result) != 0 &&		    /* An error occurred */
-	SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
-	SCpnt->sense_buffer[2] == MEDIUM_ERROR)
-      {
-	long error_sector = (SCpnt->sense_buffer[3] << 24) |
-			    (SCpnt->sense_buffer[4] << 16) |
-			    (SCpnt->sense_buffer[5] << 8) |
-			    SCpnt->sense_buffer[6];
-	int sector_size =
-	  rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].sector_size;
-	if (SCpnt->request.bh != NULL)
-	  block_sectors = SCpnt->request.bh->b_size >> 9;
-	if (sector_size == 1024)
-	  {
-	    error_sector <<= 1;
-	    if (block_sectors < 2) block_sectors = 2;
-	  }
-        else if (sector_size == 2048)
-	  {
-	    error_sector <<= 2;
-	    if (block_sectors < 4) block_sectors = 4;
-	  }
-	else if (sector_size == 256)
-	  error_sector >>= 1;
-	error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect;
-	error_sector &= ~ (block_sectors - 1);
-	good_sectors = error_sector - SCpnt->request.sector;
-	if (good_sectors < 0 || good_sectors >= this_count)
-	  good_sectors = 0;
-      }
-
-    /*
-     * First case : we assume that the command succeeded.  One of two things
-     * will happen here.  Either we will be finished, or there will be more
-     * sectors that we were unable to read last time.
-     */
-
-    if (good_sectors > 0) {
-
-	SCSI_LOG_HLCOMPLETE(1,printk("%s : %ld sectors remain.\n", nbuff,
-	       SCpnt->request.nr_sectors));
-	SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg));
-
-	if (SCpnt->use_sg) {
-	    struct scatterlist * sgpnt;
-	    int i;
-	    sgpnt = (struct scatterlist *) SCpnt->buffer;
-	    for(i=0; i<SCpnt->use_sg; i++) {
+	int result = SCpnt->result;
+	char nbuff[6];
+	int this_count = SCpnt->bufflen >> 9;
+	int good_sectors = (result == 0 ? this_count : 0);
+	int block_sectors = 1;
+
+	sd_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff);
+
+	SCSI_LOG_HLCOMPLETE(1, printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
+				      SCpnt->host->host_no,
+				      result,
+				      SCpnt->sense_buffer[0],
+				      SCpnt->sense_buffer[2]));
 
-#if 0
-		SCSI_LOG_HLCOMPLETE(3,printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address,
-		       sgpnt[i].length));
-#endif
-
-		if (sgpnt[i].alt_address) {
-		    if (SCpnt->request.cmd == READ)
-			memcpy(sgpnt[i].alt_address, sgpnt[i].address,
-			       sgpnt[i].length);
-		    scsi_free(sgpnt[i].address, sgpnt[i].length);
-		}
-	    }
+	/*
+	   Handle MEDIUM ERRORs that indicate partial success.  Since this is a
+	   relatively rare error condition, no care is taken to avoid unnecessary
+	   additional work such as memcpy's that could be avoided.
+	 */
 
-	    /* Free list of scatter-gather pointers */
-	    scsi_free(SCpnt->buffer, SCpnt->sglist_len);
-	} else {
-	    if (SCpnt->buffer != SCpnt->request.buffer) {
-		SCSI_LOG_HLCOMPLETE(3,printk("nosg: %p %p %d\n",
-                                             SCpnt->request.buffer, SCpnt->buffer,
-                                             SCpnt->bufflen));
-
-		if (SCpnt->request.cmd == READ)
-		    memcpy(SCpnt->request.buffer, SCpnt->buffer,
-			   SCpnt->bufflen);
-		scsi_free(SCpnt->buffer, SCpnt->bufflen);
-	    }
+	if (driver_byte(result) != 0 &&		/* An error occurred */
+	    SCpnt->sense_buffer[0] == 0xF0 &&	/* Sense data is valid */
+	    SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
+		long error_sector = (SCpnt->sense_buffer[3] << 24) |
+		(SCpnt->sense_buffer[4] << 16) |
+		(SCpnt->sense_buffer[5] << 8) |
+		SCpnt->sense_buffer[6];
+		int sector_size =
+		rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].sector_size;
+		if (SCpnt->request.bh != NULL)
+			block_sectors = SCpnt->request.bh->b_size >> 9;
+		if (sector_size == 1024) {
+			error_sector <<= 1;
+			if (block_sectors < 2)
+				block_sectors = 2;
+		} else if (sector_size == 2048) {
+			error_sector <<= 2;
+			if (block_sectors < 4)
+				block_sectors = 4;
+		} else if (sector_size == 256)
+			error_sector >>= 1;
+		error_sector -= sd[SD_PARTITION(SCpnt->request.rq_dev)].start_sect;
+		error_sector &= ~(block_sectors - 1);
+		good_sectors = error_sector - SCpnt->request.sector;
+		if (good_sectors < 0 || good_sectors >= this_count)
+			good_sectors = 0;
 	}
 	/*
-	 * If multiple sectors are requested in one buffer, then
-	 * they will have been finished off by the first command.
-	 * If not, then we have a multi-buffer command.
+	 * First case : we assume that the command succeeded.  One of two things
+	 * will happen here.  Either we will be finished, or there will be more
+	 * sectors that we were unable to read last time.
 	 */
-	if (SCpnt->request.nr_sectors > this_count)
-	{
-	    SCpnt->request.errors = 0;
-
-	    if (!SCpnt->request.bh)
-	    {
-		SCSI_LOG_HLCOMPLETE(2,printk("%s : handling page request, no buffer\n",
-		       nbuff));
 
+	if (good_sectors > 0) {
+
+		SCSI_LOG_HLCOMPLETE(1, printk("%s : %ld sectors remain.\n", nbuff,
+					      SCpnt->request.nr_sectors));
+		SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n ", SCpnt->use_sg));
+
+		if (SCpnt->use_sg) {
+			struct scatterlist *sgpnt;
+			int i;
+			sgpnt = (struct scatterlist *) SCpnt->buffer;
+			for (i = 0; i < SCpnt->use_sg; i++) {
+
+#if 0
+				SCSI_LOG_HLCOMPLETE(3, printk(":%p %p %d\n", sgpnt[i].alt_address, sgpnt[i].address,
+						       sgpnt[i].length));
+#endif
+
+				if (sgpnt[i].alt_address) {
+					if (SCpnt->request.cmd == READ)
+						memcpy(sgpnt[i].alt_address, sgpnt[i].address,
+						       sgpnt[i].length);
+					scsi_free(sgpnt[i].address, sgpnt[i].length);
+				}
+			}
+
+			/* Free list of scatter-gather pointers */
+			scsi_free(SCpnt->buffer, SCpnt->sglist_len);
+		} else {
+			if (SCpnt->buffer != SCpnt->request.buffer) {
+				SCSI_LOG_HLCOMPLETE(3, printk("nosg: %p %p %d\n",
+				    SCpnt->request.buffer, SCpnt->buffer,
+							SCpnt->bufflen));
+
+				if (SCpnt->request.cmd == READ)
+					memcpy(SCpnt->request.buffer, SCpnt->buffer,
+					       SCpnt->bufflen);
+				scsi_free(SCpnt->buffer, SCpnt->bufflen);
+			}
+		}
 		/*
-		 * The SCpnt->request.nr_sectors field is always done in
-		 * 512 byte sectors, even if this really isn't the case.
+		 * If multiple sectors are requested in one buffer, then
+		 * they will have been finished off by the first command.
+		 * If not, then we have a multi-buffer command.
 		 */
-		panic("sd.c: linked page request (%lx %x)",
-		      SCpnt->request.sector, this_count);
-	    }
-	}
-	SCpnt = end_scsi_request(SCpnt, 1, good_sectors);
-	if (result == 0)
-	  {
-	    requeue_sd_request(SCpnt);
-	    return;
-	  }
-    }
-
-    if (good_sectors == 0) {
-
-    /* Free up any indirection buffers we allocated for DMA purposes. */
-    if (SCpnt->use_sg) {
-	struct scatterlist * sgpnt;
-	int i;
-	sgpnt = (struct scatterlist *) SCpnt->buffer;
-	for(i=0; i<SCpnt->use_sg; i++) {
-	    SCSI_LOG_HLCOMPLETE(3,printk("err: %p %p %d\n",
-                                         SCpnt->request.buffer, SCpnt->buffer,
-                                         SCpnt->bufflen));
-	    if (sgpnt[i].alt_address) {
-		scsi_free(sgpnt[i].address, sgpnt[i].length);
-	    }
-	}
-	scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
-    } else {
-	SCSI_LOG_HLCOMPLETE(2,printk("nosgerr: %p %p %d\n",
-                                     SCpnt->request.buffer, SCpnt->buffer,
-                                     SCpnt->bufflen));
-	if (SCpnt->buffer != SCpnt->request.buffer)
-	    scsi_free(SCpnt->buffer, SCpnt->bufflen);
-    }
-    }
-
-    /*
-     * Now, if we were good little boys and girls, Santa left us a request
-     * sense buffer.  We can extract information from this, so we
-     * can choose a block to remap, etc.
-     */
+		if (SCpnt->request.nr_sectors > this_count) {
+			SCpnt->request.errors = 0;
 
-    if (driver_byte(result) != 0) {
-	if (suggestion(result) == SUGGEST_REMAP) {
-#ifdef REMAP
-	    /*
-	     * Not yet implemented.  A read will fail after being remapped,
-	     * a write will call the strategy routine again.
-	     */
-	    if rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].remap
-	    {
-		result = 0;
-	    }
-	    else
-#endif
+			if (!SCpnt->request.bh) {
+				SCSI_LOG_HLCOMPLETE(2, printk("%s : handling page request, no buffer\n",
+							      nbuff));
+
+				/*
+				 * The SCpnt->request.nr_sectors field is always done in
+				 * 512 byte sectors, even if this really isn't the case.
+				 */
+				panic("sd.c: linked page request (%lx %x)",
+				      SCpnt->request.sector, this_count);
+			}
+		}
+		SCpnt = end_scsi_request(SCpnt, 1, good_sectors);
+		if (result == 0) {
+			requeue_sd_request(SCpnt);
+			return;
+		}
 	}
+	if (good_sectors == 0) {
 
-	if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
-	    if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
-		if(rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) {
-		    /* detected disc change.  set a bit and quietly refuse
-		     * further access.
-		     */
-		    rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
-		    SCpnt = end_scsi_request(SCpnt, 0, this_count);
-		    requeue_sd_request(SCpnt);
-		    return;
-		}
-                else
-                {
-                    /*
-                     * Must have been a power glitch, or a bus reset.
-                     * Could not have been a media change, so we just retry
-                     * the request and see what happens.
-                     */
-                    requeue_sd_request(SCpnt);
-                    return;
-                }
-	    }
+		/* Free up any indirection buffers we allocated for DMA purposes. */
+		if (SCpnt->use_sg) {
+			struct scatterlist *sgpnt;
+			int i;
+			sgpnt = (struct scatterlist *) SCpnt->buffer;
+			for (i = 0; i < SCpnt->use_sg; i++) {
+				SCSI_LOG_HLCOMPLETE(3, printk("err: %p %p %d\n",
+				    SCpnt->request.buffer, SCpnt->buffer,
+							SCpnt->bufflen));
+				if (sgpnt[i].alt_address) {
+					scsi_free(sgpnt[i].address, sgpnt[i].length);
+				}
+			}
+			scsi_free(SCpnt->buffer, SCpnt->sglist_len);	/* Free list of scatter-gather pointers */
+		} else {
+			SCSI_LOG_HLCOMPLETE(2, printk("nosgerr: %p %p %d\n",
+				    SCpnt->request.buffer, SCpnt->buffer,
+						      SCpnt->bufflen));
+			if (SCpnt->buffer != SCpnt->request.buffer)
+				scsi_free(SCpnt->buffer, SCpnt->bufflen);
+		}
 	}
-
-
-	/* If we had an ILLEGAL REQUEST returned, then we may have
-	 * performed an unsupported command.  The only thing this should be
-	 * would be a ten byte read where only a six byte read was supported.
-	 * Also, on a system where READ CAPACITY failed, we have have read
-	 * past the end of the disk.
+	/*
+	 * Now, if we were good little boys and girls, Santa left us a request
+	 * sense buffer.  We can extract information from this, so we
+	 * can choose a block to remap, etc.
 	 */
 
-	if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
-	    if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) {
-		rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0;
+	if (driver_byte(result) != 0) {
+		if (suggestion(result) == SUGGEST_REMAP) {
+#ifdef REMAP
+			/*
+			 * Not yet implemented.  A read will fail after being remapped,
+			 * a write will call the strategy routine again.
+			 */
+			if rscsi_disks
+				[DEVICE_NR(SCpnt->request.rq_dev)].remap
+			{
+				result = 0;
+			}
+#endif
+		}
+		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
+			if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
+				if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->removable) {
+					/* detected disc change.  set a bit and quietly refuse
+					 * further access.
+					 */
+					rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
+					SCpnt = end_scsi_request(SCpnt, 0, this_count);
+					requeue_sd_request(SCpnt);
+					return;
+				} else {
+					/*
+					 * Must have been a power glitch, or a bus reset.
+					 * Could not have been a media change, so we just retry
+					 * the request and see what happens.
+					 */
+					requeue_sd_request(SCpnt);
+					return;
+				}
+			}
+		}
+		/* If we had an ILLEGAL REQUEST returned, then we may have
+		 * performed an unsupported command.  The only thing this should be
+		 * would be a ten byte read where only a six byte read was supported.
+		 * Also, on a system where READ CAPACITY failed, we have have read
+		 * past the end of the disk.
+		 */
+
+		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
+			if (rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten) {
+				rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].ten = 0;
+				requeue_sd_request(SCpnt);
+				result = 0;
+			} else {
+				/* ???? */
+			}
+		}
+		if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
+			printk("scsi%d: MEDIUM ERROR on channel %d, id %d, lun %d, CDB: ",
+			       SCpnt->host->host_no, (int) SCpnt->channel,
+			       (int) SCpnt->target, (int) SCpnt->lun);
+			print_command(SCpnt->cmnd);
+			print_sense("sd", SCpnt);
+			SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
+			requeue_sd_request(SCpnt);
+			return;
+		}
+	}			/* driver byte != 0 */
+	if (result) {
+		printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
+		       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
+		       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel,
+		rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
+		       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result);
+
+		if (driver_byte(result) & DRIVER_SENSE)
+			print_sense("sd", SCpnt);
+		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
 		requeue_sd_request(SCpnt);
-		result = 0;
-	    } else {
-		/* ???? */
-	    }
-	}
-
-	if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
-	    printk("scsi%d: MEDIUM ERROR on channel %d, id %d, lun %d, CDB: ",
-		   SCpnt->host->host_no, (int) SCpnt->channel,
-		   (int) SCpnt->target, (int) SCpnt->lun);
-	    print_command(SCpnt->cmnd);
-	    print_sense("sd", SCpnt);
-	    SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
-	    requeue_sd_request(SCpnt);
-	    return;
-	 }
-    }  /* driver byte != 0 */
-    if (result) {
-	printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
-	       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
-	       rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->channel,
-	   rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
-	     rscsi_disks[DEVICE_NR(SCpnt->request.rq_dev)].device->lun, result);
-
-	if (driver_byte(result) & DRIVER_SENSE)
-	    print_sense("sd", SCpnt);
-	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
-	requeue_sd_request(SCpnt);
-	return;
-    }
+		return;
+	}
 }
-
 /*
  * requeue_sd_request() is the request handler function for the sd driver.
  * Its function in life is to take block device requests, and translate
  * them to SCSI commands.
  */
 
-static void do_sd_request (void)
+static void do_sd_request(void)
 {
-    Scsi_Cmnd * SCpnt = NULL;
-    Scsi_Device * SDev;
-    struct request * req = NULL;
-    int flag = 0;
-
-    while (1==1){
-	if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
-	    return;
-	}
-
-	INIT_SCSI_REQUEST;
-        SDev = rscsi_disks[CURRENT_DEV].device;
-
-        /*
-         * If the host for this device is in error recovery mode, don't
-         * do anything at all here.  When the host leaves error recovery
-         * mode, it will automatically restart things and start queueing
-         * commands again.
-         */
-        if( SDev->host->in_recovery )
-          {
-            return;
-          }
-
-        /*
-         * I am not sure where the best place to do this is.  We need
-         * to hook in a place where we are likely to come if in user
-         * space.
-         */
-        if( SDev->was_reset )
-        {
-	    /*
-	     * We need to relock the door, but we might
-	     * be in an interrupt handler.  Only do this
-	     * from user space, since we do not want to
-	     * sleep from an interrupt.  FIXME(eric) - do this
-             * from the kernel error handling thred.
-	     */
-	    if( SDev->removable && !in_interrupt() )
-	    {
-                spin_unlock_irq(&io_request_lock);	/* FIXME!!!! */
-                scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
-		/* scsi_ioctl may allow CURRENT to change, so start over. */
-		SDev->was_reset = 0;
-                spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
-		continue;
-	    }
-	    SDev->was_reset = 0;
-        }
-
-	/* We have to be careful here. scsi_allocate_device will get a free pointer,
-	 * but there is no guarantee that it is queueable.  In normal usage,
-	 * we want to call this, because other types of devices may have the
-	 * host all tied up, and we want to make sure that we have at least
-	 * one request pending for this type of device. We can also come
-	 * through here while servicing an interrupt, because of the need to
-	 * start another command. If we call scsi_allocate_device more than once,
-	 * then the system can wedge if the command is not queueable. The
-	 * scsi_request_queueable function is safe because it checks to make sure
-	 * that the host is able to take another command before it returns
-	 * a pointer.
-	 */
-
-	if (flag++ == 0)
-	    SCpnt = scsi_allocate_device(&CURRENT,
-			   rscsi_disks[CURRENT_DEV].device, 0);
-	else SCpnt = NULL;
+	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Device *SDev;
+	struct request *req = NULL;
+	int flag = 0;
+
+	while (1 == 1) {
+		if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
+			return;
+		}
+		INIT_SCSI_REQUEST;
+		SDev = rscsi_disks[CURRENT_DEV].device;
 
-	/*
-	 * The following restore_flags leads to latency problems.  FIXME.
-	 * Using a "sti()" gets rid of the latency problems but causes
-	 * race conditions and crashes.
-	 */
+		/*
+		 * If the host for this device is in error recovery mode, don't
+		 * do anything at all here.  When the host leaves error recovery
+		 * mode, it will automatically restart things and start queueing
+		 * commands again.
+		 */
+		if (SDev->host->in_recovery) {
+			return;
+		}
+		/*
+		 * I am not sure where the best place to do this is.  We need
+		 * to hook in a place where we are likely to come if in user
+		 * space.
+		 */
+		if (SDev->was_reset) {
+			/*
+			 * We need to relock the door, but we might
+			 * be in an interrupt handler.  Only do this
+			 * from user space, since we do not want to
+			 * sleep from an interrupt.  FIXME(eric) - do this
+			 * from the kernel error handling thred.
+			 */
+			if (SDev->removable && !in_interrupt()) {
+				spin_unlock_irq(&io_request_lock);	/* FIXME!!!! */
+				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
+				/* scsi_ioctl may allow CURRENT to change, so start over. */
+				SDev->was_reset = 0;
+				spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
+				continue;
+			}
+			SDev->was_reset = 0;
+		}
+		/* We have to be careful here. scsi_allocate_device will get a free pointer,
+		 * but there is no guarantee that it is queueable.  In normal usage,
+		 * we want to call this, because other types of devices may have the
+		 * host all tied up, and we want to make sure that we have at least
+		 * one request pending for this type of device. We can also come
+		 * through here while servicing an interrupt, because of the need to
+		 * start another command. If we call scsi_allocate_device more than once,
+		 * then the system can wedge if the command is not queueable. The
+		 * scsi_request_queueable function is safe because it checks to make sure
+		 * that the host is able to take another command before it returns
+		 * a pointer.
+		 */
 
-	/* This is a performance enhancement. We dig down into the request
-	 * list and try to find a queueable request (i.e. device not busy,
-	 * and host able to accept another command. If we find one, then we
-	 * queue it. This can make a big difference on systems with more than
-	 * one disk drive.  We want to have the interrupts off when monkeying
-	 * with the request list, because otherwise the kernel might try to
-	 * slip in a request in between somewhere.
-         *
-         * FIXME(eric) - this doesn't belong at this level.  The device code in
-         * ll_rw_blk.c should know how to dig down into the device queue to
-         * figure out what it can deal with, and what it can't.  Consider
-         * possibility of pulling entire queue down into scsi layer.
-	 */
-	if (!SCpnt && sd_template.nr_dev > 1){
-	    struct request *req1;
-	    req1 = NULL;
-	    req = CURRENT;
-	    while(req){
-		SCpnt = scsi_request_queueable(req,
-                                   rscsi_disks[DEVICE_NR(req->rq_dev)].device);
-		if(SCpnt) break;
-		req1 = req;
-		req = req->next;
-	    }
-	    if (SCpnt && req->rq_status == RQ_INACTIVE) {
-		if (req == CURRENT)
-		    CURRENT = CURRENT->next;
+		if (flag++ == 0)
+			SCpnt = scsi_allocate_device(&CURRENT,
+				     rscsi_disks[CURRENT_DEV].device, 0);
 		else
-		    req1->next = req->next;
-	    }
-	}
+			SCpnt = NULL;
 
-	if (!SCpnt) return; /* Could not find anything to do */
+		/*
+		 * The following restore_flags leads to latency problems.  FIXME.
+		 * Using a "sti()" gets rid of the latency problems but causes
+		 * race conditions and crashes.
+		 */
 
-	/* Queue command */
-	requeue_sd_request(SCpnt);
-    }  /* While */
+		/* This is a performance enhancement. We dig down into the request
+		 * list and try to find a queueable request (i.e. device not busy,
+		 * and host able to accept another command. If we find one, then we
+		 * queue it. This can make a big difference on systems with more than
+		 * one disk drive.  We want to have the interrupts off when monkeying
+		 * with the request list, because otherwise the kernel might try to
+		 * slip in a request in between somewhere.
+		 *
+		 * FIXME(eric) - this doesn't belong at this level.  The device code in
+		 * ll_rw_blk.c should know how to dig down into the device queue to
+		 * figure out what it can deal with, and what it can't.  Consider
+		 * possibility of pulling entire queue down into scsi layer.
+		 */
+		if (!SCpnt && sd_template.nr_dev > 1) {
+			struct request *req1;
+			req1 = NULL;
+			req = CURRENT;
+			while (req) {
+				SCpnt = scsi_request_queueable(req,
+							       rscsi_disks[DEVICE_NR(req->rq_dev)].device);
+				if (SCpnt)
+					break;
+				req1 = req;
+				req = req->next;
+			}
+			if (SCpnt && req->rq_status == RQ_INACTIVE) {
+				if (req == CURRENT)
+					CURRENT = CURRENT->next;
+				else
+					req1->next = req->next;
+			}
+		}
+		if (!SCpnt)
+			return;	/* Could not find anything to do */
+
+		/* Queue command */
+		requeue_sd_request(SCpnt);
+	}			/* While */
 }
 
-static void requeue_sd_request (Scsi_Cmnd * SCpnt)
+static void requeue_sd_request(Scsi_Cmnd * SCpnt)
 {
-    int dev, devm, block, this_count;
-    unsigned char cmd[10];
-    char nbuff[6];
-    int bounce_size, contiguous;
-    int max_sg;
-    struct buffer_head * bh, *bhp;
-    char * buff, *bounce_buffer;
-
- repeat:
-
-    if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
-	do_sd_request();
-	return;
-    }
+	int dev, devm, block, this_count;
+	unsigned char cmd[10];
+	char nbuff[6];
+	int bounce_size, contiguous;
+	int max_sg;
+	struct buffer_head *bh, *bhp;
+	char *buff, *bounce_buffer;
+
+repeat:
+
+	if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
+		do_sd_request();
+		return;
+	}
+	devm = SD_PARTITION(SCpnt->request.rq_dev);
+	dev = DEVICE_NR(SCpnt->request.rq_dev);
 
-    devm =  SD_PARTITION(SCpnt->request.rq_dev);
-    dev = DEVICE_NR(SCpnt->request.rq_dev);
+	block = SCpnt->request.sector;
+	this_count = 0;
 
-    block = SCpnt->request.sector;
-    this_count = 0;
+	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block));
 
-    SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block));
-
-    if (devm >= (sd_template.dev_max << 4) ||
-	!rscsi_disks[dev].device ||
-	!rscsi_disks[dev].device->online ||
-	block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
-    {
-        SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
-	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-        SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt));
-	goto repeat;
-    }
+	if (devm >= (sd_template.dev_max << 4) ||
+	    !rscsi_disks[dev].device ||
+	    !rscsi_disks[dev].device->online ||
+	    block + SCpnt->request.nr_sectors > sd[devm].nr_sects) {
+		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
+		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
+		goto repeat;
+	}
+	block += sd[devm].start_sect;
 
-    block += sd[devm].start_sect;
+	if (rscsi_disks[dev].device->changed) {
+		/*
+		 * quietly refuse to do anything to a changed disc until the changed
+		 * bit has been reset
+		 */
+		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+		goto repeat;
+	}
+	sd_devname(devm >> 4, nbuff);
+	SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n",
+				   nbuff, dev, block));
 
-    if (rscsi_disks[dev].device->changed)
-    {
 	/*
-	 * quietly refuse to do anything to a changed disc until the changed
-	 * bit has been reset
+	 * If we have a 1K hardware sectorsize, prevent access to single
+	 * 512 byte sectors.  In theory we could handle this - in fact
+	 * the scsi cdrom driver must be able to handle this because
+	 * we typically use 1K blocksizes, and cdroms typically have
+	 * 2K hardware sectorsizes.  Of course, things are simpler
+	 * with the cdrom, since it is read-only.  For performance
+	 * reasons, the filesystems should be able to handle this
+	 * and not force the scsi disk driver to use bounce buffers
+	 * for this.
 	 */
-	/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
-	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-	goto repeat;
-    }
-
-    sd_devname(devm >> 4, nbuff);
-    SCSI_LOG_HLQUEUE(2,printk("%s : real dev = /dev/%d, block = %d\n",
-	   nbuff, dev, block));
-
-    /*
-     * If we have a 1K hardware sectorsize, prevent access to single
-     * 512 byte sectors.  In theory we could handle this - in fact
-     * the scsi cdrom driver must be able to handle this because
-     * we typically use 1K blocksizes, and cdroms typically have
-     * 2K hardware sectorsizes.  Of course, things are simpler
-     * with the cdrom, since it is read-only.  For performance
-     * reasons, the filesystems should be able to handle this
-     * and not force the scsi disk driver to use bounce buffers
-     * for this.
-     */
-    if (rscsi_disks[dev].sector_size == 1024)
-	if((block & 1) || (SCpnt->request.nr_sectors & 1)) {
-	    printk("sd.c:Bad block number/count requested");
-	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-	    goto repeat;
-	}
-
-     if (rscsi_disks[dev].sector_size == 2048)
- 	if((block & 3) || (SCpnt->request.nr_sectors & 3)) {
- 	    printk("sd.c:Bad block number/count requested");
- 	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
- 	    goto repeat;
- 	}
-    if (rscsi_disks[dev].sector_size == 4096) 
-	if((block & 7) || (SCpnt->request.nr_sectors & 7)) {
-	    printk("sd.cBad block number/count requested");
-	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-	    goto repeat;
-	}
-     
-    switch (SCpnt->request.cmd)
-    {
-    case WRITE :
-	if (!rscsi_disks[dev].device->writeable)
-	{
-	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-	    goto repeat;
-	}
-	cmd[0] = WRITE_6;
-	break;
-    case READ :
-	cmd[0] = READ_6;
-	break;
-    default :
-	panic ("Unknown sd command %d\n", SCpnt->request.cmd);
-    }
-
-    SCpnt->this_count = 0;
-
-    /* If the host adapter can deal with very large scatter-gather
-     * requests, it is a waste of time to cluster
-     */
-    contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1);
-    bounce_buffer = NULL;
-    bounce_size = (SCpnt->request.nr_sectors << 9);
-
-    /* First see if we need a bounce buffer for this request. If we do, make
-     * sure that we can allocate a buffer. Do not waste space by allocating
-     * a bounce buffer if we are straddling the 16Mb line
-     */
-    if (contiguous && SCpnt->request.bh &&
-      virt_to_phys(SCpnt->request.bh->b_data)
-	+ (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD
-	&& SCpnt->host->unchecked_isa_dma) {
-      if(virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
-	    bounce_buffer = (char *) scsi_malloc(bounce_size);
-	if(!bounce_buffer) contiguous = 0;
-    }
-
-    if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
-	for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
-	    bhp = bhp->b_reqnext) {
-	    if(!CONTIGUOUS_BUFFERS(bh,bhp)) {
-		if(bounce_buffer) scsi_free(bounce_buffer, bounce_size);
-		contiguous = 0;
+	if (rscsi_disks[dev].sector_size == 1024)
+		if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {
+			printk("sd.c:Bad block number/count requested");
+			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+			goto repeat;
+		}
+	if (rscsi_disks[dev].sector_size == 2048)
+		if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {
+			printk("sd.c:Bad block number/count requested");
+			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+			goto repeat;
+		}
+	if (rscsi_disks[dev].sector_size == 4096)
+		if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {
+			printk("sd.cBad block number/count requested");
+			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+			goto repeat;
+		}
+	switch (SCpnt->request.cmd) {
+	case WRITE:
+		if (!rscsi_disks[dev].device->writeable) {
+			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+			goto repeat;
+		}
+		cmd[0] = WRITE_6;
+		break;
+	case READ:
+		cmd[0] = READ_6;
 		break;
-	    }
+	default:
+		panic("Unknown sd command %d\n", SCpnt->request.cmd);
 	}
-    if (!SCpnt->request.bh || contiguous) {
 
-	/* case of page request (i.e. raw device), or unlinked buffer */
-	this_count = SCpnt->request.nr_sectors;
-	buff = SCpnt->request.buffer;
-	SCpnt->use_sg = 0;
-
-    } else if (SCpnt->host->sg_tablesize == 0 ||
-	       (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) {
-
-	/* Case of host adapter that cannot scatter-gather.  We also
-	 * come here if we are running low on DMA buffer memory.  We set
-	 * a threshold higher than that we would need for this request so
-	 * we leave room for other requests.  Even though we would not need
-	 * it all, we need to be conservative, because if we run low enough
-	 * we have no choice but to panic.
+	SCpnt->this_count = 0;
+
+	/* If the host adapter can deal with very large scatter-gather
+	 * requests, it is a waste of time to cluster
+	 */
+	contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 : 1);
+	bounce_buffer = NULL;
+	bounce_size = (SCpnt->request.nr_sectors << 9);
+
+	/* First see if we need a bounce buffer for this request. If we do, make
+	 * sure that we can allocate a buffer. Do not waste space by allocating
+	 * a bounce buffer if we are straddling the 16Mb line
 	 */
-	if (SCpnt->host->sg_tablesize != 0 &&
-	    scsi_need_isa_buffer &&
-	    scsi_dma_free_sectors <= 10)
-	    printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
-
-	this_count = SCpnt->request.current_nr_sectors;
-	buff = SCpnt->request.buffer;
-	SCpnt->use_sg = 0;
-
-    } else {
-
-	/* Scatter-gather capable host adapter */
-	struct scatterlist * sgpnt;
-	int count, this_count_max;
-	int counted;
+	if (contiguous && SCpnt->request.bh &&
+	    virt_to_phys(SCpnt->request.bh->b_data)
+	    + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD
+	    && SCpnt->host->unchecked_isa_dma) {
+		if (virt_to_phys(SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
+			bounce_buffer = (char *) scsi_malloc(bounce_size);
+		if (!bounce_buffer)
+			contiguous = 0;
+	}
+	if (contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
+		for (bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
+		     bhp = bhp->b_reqnext) {
+			if (!CONTIGUOUS_BUFFERS(bh, bhp)) {
+				if (bounce_buffer)
+					scsi_free(bounce_buffer, bounce_size);
+				contiguous = 0;
+				break;
+			}
+		}
+	if (!SCpnt->request.bh || contiguous) {
+
+		/* case of page request (i.e. raw device), or unlinked buffer */
+		this_count = SCpnt->request.nr_sectors;
+		buff = SCpnt->request.buffer;
+		SCpnt->use_sg = 0;
+
+	} else if (SCpnt->host->sg_tablesize == 0 ||
+		 (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) {
+
+		/* Case of host adapter that cannot scatter-gather.  We also
+		 * come here if we are running low on DMA buffer memory.  We set
+		 * a threshold higher than that we would need for this request so
+		 * we leave room for other requests.  Even though we would not need
+		 * it all, we need to be conservative, because if we run low enough
+		 * we have no choice but to panic.
+		 */
+		if (SCpnt->host->sg_tablesize != 0 &&
+		    scsi_need_isa_buffer &&
+		    scsi_dma_free_sectors <= 10)
+			printk("Warning: SCSI DMA buffer space running low.  Using non scatter-gather I/O.\n");
+
+		this_count = SCpnt->request.current_nr_sectors;
+		buff = SCpnt->request.buffer;
+		SCpnt->use_sg = 0;
 
-	bh = SCpnt->request.bh;
-	this_count = 0;
-	this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
-	count = 0;
-	bhp = NULL;
-	while(bh) {
-	    if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
-	    if(!bhp || !CONTIGUOUS_BUFFERS(bhp,bh) ||
-	       !CLUSTERABLE_DEVICE(SCpnt) ||
-	       (SCpnt->host->unchecked_isa_dma &&
-		virt_to_phys(bh->b_data-1) == ISA_DMA_THRESHOLD)) {
-		if (count < SCpnt->host->sg_tablesize) count++;
-		else break;
-	    }
-	    this_count += (bh->b_size >> 9);
-	    bhp = bh;
-	    bh = bh->b_reqnext;
-	}
-#if 0
-	if(SCpnt->host->unchecked_isa_dma &&
-	 virt_to_phys(SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
-#endif
-	SCpnt->use_sg = count;  /* Number of chains */
-	/* scsi_malloc can only allocate in chunks of 512 bytes */
-	count  = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;
-
-	SCpnt->sglist_len = count;
-	max_sg = count / sizeof(struct scatterlist);
-	if(SCpnt->host->sg_tablesize < max_sg)
-	    max_sg = SCpnt->host->sg_tablesize;
-	sgpnt = (struct scatterlist * ) scsi_malloc(count);
-	if (!sgpnt) {
-	    printk("Warning - running *really* short on DMA buffers\n");
-	    SCpnt->use_sg = 0;    /* No memory left - bail out */
-	    this_count = SCpnt->request.current_nr_sectors;
-	    buff = SCpnt->request.buffer;
 	} else {
-	    memset(sgpnt, 0, count);  /* Zero so it is easy to fill, but only
-				       * if memory is available
-				       */
-	    buff = (char *) sgpnt;
-	    counted = 0;
-	    for(count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext;
-		count < SCpnt->use_sg && bh;
-		count++, bh = bhp) {
-
-		bhp = bh->b_reqnext;
-
-		if(!sgpnt[count].address) sgpnt[count].address = bh->b_data;
-		sgpnt[count].length += bh->b_size;
-		counted += bh->b_size >> 9;
-
-		if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
-		    ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
-		    !sgpnt[count].alt_address) {
-		    sgpnt[count].alt_address = sgpnt[count].address;
-		    /* We try to avoid exhausting the DMA pool, since it is
-		     * easier to control usage here. In other places we might
-		     * have a more pressing need, and we would be screwed if
-		     * we ran out */
-		    if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
-			sgpnt[count].address = NULL;
-		    } else {
-			sgpnt[count].address =
-			    (char *) scsi_malloc(sgpnt[count].length);
-		    }
-		    /* If we start running low on DMA buffers, we abort the
-		     * scatter-gather operation, and free all of the memory
-		     * we have allocated.  We want to ensure that all scsi
-		     * operations are able to do at least a non-scatter/gather
-		     * operation */
-		    if(sgpnt[count].address == NULL){ /* Out of dma memory */
-#if 0
-			printk("Warning: Running low on SCSI DMA buffers");
-			/* Try switching back to a non s-g operation. */
-			while(--count >= 0){
-			    if(sgpnt[count].alt_address)
-				scsi_free(sgpnt[count].address,
-					  sgpnt[count].length);
+
+		/* Scatter-gather capable host adapter */
+		struct scatterlist *sgpnt;
+		int count, this_count_max;
+		int counted;
+
+		bh = SCpnt->request.bh;
+		this_count = 0;
+		this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
+		count = 0;
+		bhp = NULL;
+		while (bh) {
+			if ((this_count + (bh->b_size >> 9)) > this_count_max)
+				break;
+			if (!bhp || !CONTIGUOUS_BUFFERS(bhp, bh) ||
+			    !CLUSTERABLE_DEVICE(SCpnt) ||
+			    (SCpnt->host->unchecked_isa_dma &&
+			     virt_to_phys(bh->b_data - 1) == ISA_DMA_THRESHOLD)) {
+				if (count < SCpnt->host->sg_tablesize)
+					count++;
+				else
+					break;
 			}
+			this_count += (bh->b_size >> 9);
+			bhp = bh;
+			bh = bh->b_reqnext;
+		}
+#if 0
+		if (SCpnt->host->unchecked_isa_dma &&
+		    virt_to_phys(SCpnt->request.bh->b_data - 1) == ISA_DMA_THRESHOLD)
+			count--;
+#endif
+		SCpnt->use_sg = count;	/* Number of chains */
+		/* scsi_malloc can only allocate in chunks of 512 bytes */
+		count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;
+
+		SCpnt->sglist_len = count;
+		max_sg = count / sizeof(struct scatterlist);
+		if (SCpnt->host->sg_tablesize < max_sg)
+			max_sg = SCpnt->host->sg_tablesize;
+		sgpnt = (struct scatterlist *) scsi_malloc(count);
+		if (!sgpnt) {
+			printk("Warning - running *really* short on DMA buffers\n");
+			SCpnt->use_sg = 0;	/* No memory left - bail out */
 			this_count = SCpnt->request.current_nr_sectors;
 			buff = SCpnt->request.buffer;
-			SCpnt->use_sg = 0;
-			scsi_free(sgpnt, SCpnt->sglist_len);
+		} else {
+			memset(sgpnt, 0, count);	/* Zero so it is easy to fill, but only
+							 * if memory is available
+							 */
+			buff = (char *) sgpnt;
+			counted = 0;
+			for (count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext;
+			     count < SCpnt->use_sg && bh;
+			     count++, bh = bhp) {
+
+				bhp = bh->b_reqnext;
+
+				if (!sgpnt[count].address)
+					sgpnt[count].address = bh->b_data;
+				sgpnt[count].length += bh->b_size;
+				counted += bh->b_size >> 9;
+
+				if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
+				    ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
+				    !sgpnt[count].alt_address) {
+					sgpnt[count].alt_address = sgpnt[count].address;
+					/* We try to avoid exhausting the DMA pool, since it is
+					 * easier to control usage here. In other places we might
+					 * have a more pressing need, and we would be screwed if
+					 * we ran out */
+					if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
+						sgpnt[count].address = NULL;
+					} else {
+						sgpnt[count].address =
+						    (char *) scsi_malloc(sgpnt[count].length);
+					}
+					/* If we start running low on DMA buffers, we abort the
+					 * scatter-gather operation, and free all of the memory
+					 * we have allocated.  We want to ensure that all scsi
+					 * operations are able to do at least a non-scatter/gather
+					 * operation */
+					if (sgpnt[count].address == NULL) {	/* Out of dma memory */
+#if 0
+						printk("Warning: Running low on SCSI DMA buffers");
+						/* Try switching back to a non s-g operation. */
+						while (--count >= 0) {
+							if (sgpnt[count].alt_address)
+								scsi_free(sgpnt[count].address,
+									  sgpnt[count].length);
+						}
+						this_count = SCpnt->request.current_nr_sectors;
+						buff = SCpnt->request.buffer;
+						SCpnt->use_sg = 0;
+						scsi_free(sgpnt, SCpnt->sglist_len);
 #endif
-			SCpnt->use_sg = count;
-			this_count = counted -= bh->b_size >> 9;
-			break;
-		    }
+						SCpnt->use_sg = count;
+						this_count = counted -= bh->b_size >> 9;
+						break;
+					}
+				}
+				/* Only cluster buffers if we know that we can supply DMA
+				 * buffers large enough to satisfy the request. Do not cluster
+				 * a new request if this would mean that we suddenly need to
+				 * start using DMA bounce buffers */
+				if (bhp && CONTIGUOUS_BUFFERS(bh, bhp)
+				    && CLUSTERABLE_DEVICE(SCpnt)) {
+					char *tmp;
+
+					if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length +
+					    bhp->b_size - 1 > ISA_DMA_THRESHOLD &&
+					    (SCpnt->host->unchecked_isa_dma) &&
+					    !sgpnt[count].alt_address)
+						continue;
+
+					if (!sgpnt[count].alt_address) {
+						count--;
+						continue;
+					}
+					if (scsi_dma_free_sectors > 10)
+						tmp = (char *) scsi_malloc(sgpnt[count].length
+							  + bhp->b_size);
+					else {
+						tmp = NULL;
+						max_sg = SCpnt->use_sg;
+					}
+					if (tmp) {
+						scsi_free(sgpnt[count].address, sgpnt[count].length);
+						sgpnt[count].address = tmp;
+						count--;
+						continue;
+					}
+					/* If we are allowed another sg chain, then increment
+					 * counter so we can insert it.  Otherwise we will end
+					 up truncating */
+
+					if (SCpnt->use_sg < max_sg)
+						SCpnt->use_sg++;
+				}	/* contiguous buffers */
+			}	/* for loop */
+
+			/* This is actually how many we are going to transfer */
+			this_count = counted;
+
+			if (count < SCpnt->use_sg || SCpnt->use_sg
+			    > SCpnt->host->sg_tablesize) {
+				bh = SCpnt->request.bh;
+				printk("Use sg, count %d %x %d\n",
+				       SCpnt->use_sg, count, scsi_dma_free_sectors);
+				printk("maxsg = %x, counted = %d this_count = %d\n",
+				       max_sg, counted, this_count);
+				while (bh) {
+					printk("[%p %x] ", bh->b_data, bh->b_size);
+					bh = bh->b_reqnext;
+				}
+				if (SCpnt->use_sg < 16)
+					for (count = 0; count < SCpnt->use_sg; count++)
+						printk("{%d:%p %p %d}  ", count,
+						    sgpnt[count].address,
+						sgpnt[count].alt_address,
+						    sgpnt[count].length);
+				panic("Ooops");
+			}
+			if (SCpnt->request.cmd == WRITE)
+				for (count = 0; count < SCpnt->use_sg; count++)
+					if (sgpnt[count].alt_address)
+						memcpy(sgpnt[count].address, sgpnt[count].alt_address,
+						    sgpnt[count].length);
+		}		/* Able to malloc sgpnt */
+	}			/* Host adapter capable of scatter-gather */
+
+	/* Now handle the possibility of DMA to addresses > 16Mb */
+
+	if (SCpnt->use_sg == 0) {
+		if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD &&
+		    (SCpnt->host->unchecked_isa_dma)) {
+			if (bounce_buffer)
+				buff = bounce_buffer;
+			else
+				buff = (char *) scsi_malloc(this_count << 9);
+			if (buff == NULL) {	/* Try backing off a bit if we are low on mem */
+				this_count = SCpnt->request.current_nr_sectors;
+				buff = (char *) scsi_malloc(this_count << 9);
+				if (!buff)
+					panic("Ran out of DMA buffers.");
+			}
+			if (SCpnt->request.cmd == WRITE)
+				memcpy(buff, (char *) SCpnt->request.buffer, this_count << 9);
 		}
+	}
+	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
+				   nbuff,
+		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+				 this_count, SCpnt->request.nr_sectors));
+
+	cmd[1] = (SCpnt->lun << 5) & 0xe0;
+
+	if (rscsi_disks[dev].sector_size == 4096) {
+		if (block & 7)
+			panic("sd.c:Bad block number requested");
+		if (this_count & 7)
+			panic("sd.c:Bad block number requested");
+		block = block >> 3;
+		this_count = block >> 3;
+	}
+	if (rscsi_disks[dev].sector_size == 2048) {
+		if (block & 3)
+			panic("sd.c:Bad block number requested");
+		if (this_count & 3)
+			panic("sd.c:Bad block number requested");
+		block = block >> 2;
+		this_count = this_count >> 2;
+	}
+	if (rscsi_disks[dev].sector_size == 1024) {
+		if (block & 1)
+			panic("sd.c:Bad block number requested");
+		if (this_count & 1)
+			panic("sd.c:Bad block number requested");
+		block = block >> 1;
+		this_count = this_count >> 1;
+	}
+	if (rscsi_disks[dev].sector_size == 256) {
+		block = block << 1;
+		this_count = this_count << 1;
+	}
+	if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) {
+		if (this_count > 0xffff)
+			this_count = 0xffff;
+
+		cmd[0] += READ_10 - READ_6;
+		cmd[2] = (unsigned char) (block >> 24) & 0xff;
+		cmd[3] = (unsigned char) (block >> 16) & 0xff;
+		cmd[4] = (unsigned char) (block >> 8) & 0xff;
+		cmd[5] = (unsigned char) block & 0xff;
+		cmd[6] = cmd[9] = 0;
+		cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
+		cmd[8] = (unsigned char) this_count & 0xff;
+	} else {
+		if (this_count > 0xff)
+			this_count = 0xff;
 
-		/* Only cluster buffers if we know that we can supply DMA
-		 * buffers large enough to satisfy the request. Do not cluster
-		 * a new request if this would mean that we suddenly need to
-		 * start using DMA bounce buffers */
-		if(bhp && CONTIGUOUS_BUFFERS(bh,bhp)
-		   && CLUSTERABLE_DEVICE(SCpnt)) {
-		    char * tmp;
-
-		  if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length +
-			bhp->b_size - 1 > ISA_DMA_THRESHOLD &&
-			(SCpnt->host->unchecked_isa_dma) &&
-			!sgpnt[count].alt_address) continue;
-
-		    if(!sgpnt[count].alt_address) {count--; continue; }
-		    if(scsi_dma_free_sectors > 10)
-			tmp = (char *) scsi_malloc(sgpnt[count].length
-						   + bhp->b_size);
-		    else {
-			tmp = NULL;
-			max_sg = SCpnt->use_sg;
-		    }
-		    if(tmp){
-			scsi_free(sgpnt[count].address, sgpnt[count].length);
-			sgpnt[count].address = tmp;
-			count--;
-			continue;
-		    }
-
-		    /* If we are allowed another sg chain, then increment
-		     * counter so we can insert it.  Otherwise we will end
-		     up truncating */
-
-		    if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
-		}  /* contiguous buffers */
-	    } /* for loop */
+		cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+		cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+		cmd[3] = (unsigned char) block & 0xff;
+		cmd[4] = (unsigned char) this_count;
+		cmd[5] = 0;
+	}
 
-	    /* This is actually how many we are going to transfer */
-	    this_count = counted;
+	/*
+	 * We shouldn't disconnect in the middle of a sector, so with a dumb
+	 * host adapter, it's safe to assume that we can at least transfer
+	 * this many bytes between each connect / disconnect.
+	 */
 
-	    if(count < SCpnt->use_sg || SCpnt->use_sg
-	       > SCpnt->host->sg_tablesize){
-		bh = SCpnt->request.bh;
-		printk("Use sg, count %d %x %d\n",
-		       SCpnt->use_sg, count, scsi_dma_free_sectors);
-		printk("maxsg = %x, counted = %d this_count = %d\n",
-		       max_sg, counted, this_count);
-		while(bh){
-		    printk("[%p %x] ", bh->b_data, bh->b_size);
-		    bh = bh->b_reqnext;
-		}
-		if(SCpnt->use_sg < 16)
-		    for(count=0; count<SCpnt->use_sg; count++)
-			printk("{%d:%p %p %d}  ", count,
-			       sgpnt[count].address,
-			       sgpnt[count].alt_address,
-			       sgpnt[count].length);
-		panic("Ooops");
-	    }
-
-	    if (SCpnt->request.cmd == WRITE)
-		for(count=0; count<SCpnt->use_sg; count++)
-		    if(sgpnt[count].alt_address)
-			memcpy(sgpnt[count].address, sgpnt[count].alt_address,
-			       sgpnt[count].length);
-	}  /* Able to malloc sgpnt */
-    }  /* Host adapter capable of scatter-gather */
-
-    /* Now handle the possibility of DMA to addresses > 16Mb */
-
-    if(SCpnt->use_sg == 0){
-      if (virt_to_phys(buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD &&
-	    (SCpnt->host->unchecked_isa_dma)) {
-	    if(bounce_buffer)
-		buff = bounce_buffer;
-	    else
-		buff = (char *) scsi_malloc(this_count << 9);
-	    if(buff == NULL) {  /* Try backing off a bit if we are low on mem*/
-		this_count = SCpnt->request.current_nr_sectors;
-		buff = (char *) scsi_malloc(this_count << 9);
-		if(!buff) panic("Ran out of DMA buffers.");
-	    }
-	    if (SCpnt->request.cmd == WRITE)
-		memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
-	}
-    }
-    SCSI_LOG_HLQUEUE(2,printk("%s : %s %d/%ld 512 byte blocks.\n",
-                              nbuff,
-                              (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
-                              this_count, SCpnt->request.nr_sectors));
-
-    cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
-     if (rscsi_disks[dev].sector_size == 4096){
-	if(block & 7) panic("sd.c:Bad block number requested");
-	if(this_count & 7) panic("sd.c:Bad block number requested");
-	block = block >> 3;
-	this_count = block >> 3;
-     }
-
-     if (rscsi_disks[dev].sector_size == 2048){
- 	if(block & 3) panic("sd.c:Bad block number requested");
- 	if(this_count & 3) panic("sd.c:Bad block number requested");
- 	block = block >> 2;
- 	this_count = this_count >> 2;
-     }
-     
-    if (rscsi_disks[dev].sector_size == 1024){
-	if(block & 1) panic("sd.c:Bad block number requested");
-	if(this_count & 1) panic("sd.c:Bad block number requested");
-	block = block >> 1;
-	this_count = this_count >> 1;
-    }
-
-    if (rscsi_disks[dev].sector_size == 256){
-	block = block << 1;
-	this_count = this_count << 1;
-    }
-
-    if (((this_count > 0xff) ||  (block > 0x1fffff)) && rscsi_disks[dev].ten)
-    {
-	if (this_count > 0xffff)
-	    this_count = 0xffff;
-
-	cmd[0] += READ_10 - READ_6 ;
-	cmd[2] = (unsigned char) (block >> 24) & 0xff;
-	cmd[3] = (unsigned char) (block >> 16) & 0xff;
-	cmd[4] = (unsigned char) (block >> 8) & 0xff;
-	cmd[5] = (unsigned char) block & 0xff;
-	cmd[6] = cmd[9] = 0;
-	cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
-	cmd[8] = (unsigned char) this_count & 0xff;
-    }
-    else
-    {
-	if (this_count > 0xff)
-	    this_count = 0xff;
-
-	cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-	cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-	cmd[3] = (unsigned char) block & 0xff;
-	cmd[4] = (unsigned char) this_count;
-	cmd[5] = 0;
-    }
-
-    /*
-     * We shouldn't disconnect in the middle of a sector, so with a dumb
-     * host adapter, it's safe to assume that we can at least transfer
-     * this many bytes between each connect / disconnect.
-     */
-
-    SCpnt->transfersize = rscsi_disks[dev].sector_size;
-    SCpnt->underflow = this_count << 9;
-    SCpnt->cmd_len = 0;
-    scsi_do_cmd (SCpnt, (void *) cmd, buff,
-		 this_count * rscsi_disks[dev].sector_size,
-		 rw_intr,
-		 (SCpnt->device->type == TYPE_DISK ?
-		  SD_TIMEOUT : SD_MOD_TIMEOUT),
-		 MAX_RETRIES);
+	SCpnt->transfersize = rscsi_disks[dev].sector_size;
+	SCpnt->underflow = this_count << 9;
+	SCpnt->cmd_len = 0;
+	scsi_do_cmd(SCpnt, (void *) cmd, buff,
+		    this_count * rscsi_disks[dev].sector_size,
+		    rw_intr,
+		    (SCpnt->device->type == TYPE_DISK ?
+		     SD_TIMEOUT : SD_MOD_TIMEOUT),
+		    MAX_RETRIES);
 }
 
-static int check_scsidisk_media_change(kdev_t full_dev){
-    int retval;
-    int target;
-    struct inode inode;
-    int flag = 0;
-
-    target =  DEVICE_NR(full_dev);
-
-    if (target >= sd_template.dev_max ||
-	!rscsi_disks[target].device) {
-	printk("SCSI disk request error: invalid device.\n");
-	return 0;
-    }
+static int check_scsidisk_media_change(kdev_t full_dev)
+{
+	int retval;
+	int target;
+	struct inode inode;
+	int flag = 0;
+
+	target = DEVICE_NR(full_dev);
+
+	if (target >= sd_template.dev_max ||
+	    !rscsi_disks[target].device) {
+		printk("SCSI disk request error: invalid device.\n");
+		return 0;
+	}
+	if (!rscsi_disks[target].device->removable)
+		return 0;
 
-    if(!rscsi_disks[target].device->removable) return 0;
+	/*
+	 * If the device is offline, don't send any commands - just pretend as if
+	 * the command failed.  If the device ever comes back online, we can deal with
+	 * it then.  It is only because of unrecoverable errors that we would ever
+	 * take a device offline in the first place.
+	 */
+	if (rscsi_disks[target].device->online == FALSE) {
+		rscsi_disks[target].ready = 0;
+		rscsi_disks[target].device->changed = 1;
+		return 1;	/* This will force a flush, if called from
+				 * check_disk_change */
+	}
+	inode.i_rdev = full_dev;	/* This is all we really need here */
+
+	/* Using Start/Stop enables differentiation between drive with
+	 * no cartridge loaded - NOT READY, drive with changed cartridge -
+	 * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
+	 * This also handles drives that auto spin down. eg iomega jaz 1GB
+	 * as this will spin up the drive.
+	 */
+	retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
 
-    /*
-     * If the device is offline, don't send any commands - just pretend as if
-     * the command failed.  If the device ever comes back online, we can deal with
-     * it then.  It is only because of unrecoverable errors that we would ever
-     * take a device offline in the first place.
-     */
-    if( rscsi_disks[target].device->online == FALSE )
-    {
-	rscsi_disks[target].ready = 0;
-	rscsi_disks[target].device->changed = 1;
-	return 1; /* This will force a flush, if called from
-		   * check_disk_change */
-    }
-
-    inode.i_rdev = full_dev;  /* This is all we really need here */
-
-    /* Using Start/Stop enables differentiation between drive with
-     * no cartridge loaded - NOT READY, drive with changed cartridge -
-     * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
-     * This also handles drives that auto spin down. eg iomega jaz 1GB
-     * as this will spin up the drive.
-     */
-    retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_START_UNIT, 0);
-    
-    if(retval){ /* Unable to test, unit probably not ready.  This usually
-		 * means there is no disc in the drive.  Mark as changed,
-		 * and we will figure it out later once the drive is
-		 * available again.  */
-
-	rscsi_disks[target].ready = 0;
-	rscsi_disks[target].device->changed = 1;
-	return 1; /* This will force a flush, if called from
-		   * check_disk_change */
-    }
-
-    /*
-     * for removable scsi disk ( FLOPTICAL ) we have to recognise the
-     * presence of disk in the drive. This is kept in the Scsi_Disk
-     * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
-     */
-
-    rscsi_disks[target].ready = 1;	/* FLOPTICAL */
-
-    retval = rscsi_disks[target].device->changed;
-    if(!flag) rscsi_disks[target].device->changed = 0;
-    return retval;
+	if (retval) {		/* Unable to test, unit probably not ready.  This usually
+				 * means there is no disc in the drive.  Mark as changed,
+				 * and we will figure it out later once the drive is
+				 * available again.  */
+
+		rscsi_disks[target].ready = 0;
+		rscsi_disks[target].device->changed = 1;
+		return 1;	/* This will force a flush, if called from
+				 * check_disk_change */
+	}
+	/*
+	 * for removable scsi disk ( FLOPTICAL ) we have to recognise the
+	 * presence of disk in the drive. This is kept in the Scsi_Disk
+	 * struct and tested at open !  Daniel Roche ( dan@lectra.fr )
+	 */
+
+	rscsi_disks[target].ready = 1;	/* FLOPTICAL */
+
+	retval = rscsi_disks[target].device->changed;
+	if (!flag)
+		rscsi_disks[target].device->changed = 0;
+	return retval;
 }
 
-static void sd_init_done (Scsi_Cmnd * SCpnt)
+static void sd_init_done(Scsi_Cmnd * SCpnt)
 {
-    struct request * req;
+	struct request *req;
 
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
 
-    if (req->sem != NULL) {
-	up(req->sem);
-    }
+	if (req->sem != NULL) {
+		up(req->sem);
+	}
 }
-
 static int sd_init_onedisk(int i)
 {
-    unsigned char cmd[10];
-    char          nbuff[6];
-    unsigned char *buffer;
-    unsigned long spintime;
-    int the_result, retries;
-    Scsi_Cmnd * SCpnt;
-
-    /*
-     * Get the name of the disk, in case we need to log it somewhere.
-     */
-    sd_devname(i, nbuff);
-
-    /*
-     * If the device is offline, don't try and read capacity or any of the other
-     * nicities.
-     */
-    if( rscsi_disks[i].device->online == FALSE )
-    {
-        return i;
-    }
-
-    spin_lock_irq(&io_request_lock);
-
-    /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
-     * considered a fatal error, and many devices report such an error
-     * just after a scsi bus reset.
-     */
-
-    SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
-    buffer = (unsigned char *) scsi_malloc(512);
-
-    spintime = 0;
-
-    /* Spin up drives, as required.  Only do this at boot time */
-    /* Spinup needs to be done for module loads too. */
-	do{
-	    retries = 0;
-	    while(retries < 3)
-	    {
-		cmd[0] = TEST_UNIT_READY;
+	unsigned char cmd[10];
+	char nbuff[6];
+	unsigned char *buffer;
+	unsigned long spintime;
+	int the_result, retries;
+	Scsi_Cmnd *SCpnt;
+
+	/*
+	 * Get the name of the disk, in case we need to log it somewhere.
+	 */
+	sd_devname(i, nbuff);
+
+	/*
+	 * If the device is offline, don't try and read capacity or any of the other
+	 * nicities.
+	 */
+	if (rscsi_disks[i].device->online == FALSE) {
+		return i;
+	}
+	spin_lock_irq(&io_request_lock);
+
+	/* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
+	 * considered a fatal error, and many devices report such an error
+	 * just after a scsi bus reset.
+	 */
+
+	SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
+	buffer = (unsigned char *) scsi_malloc(512);
+
+	spintime = 0;
+
+	/* Spin up drives, as required.  Only do this at boot time */
+	/* Spinup needs to be done for module loads too. */
+	do {
+		retries = 0;
+		while (retries < 3) {
+			cmd[0] = TEST_UNIT_READY;
+			cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+			memset((void *) &cmd[2], 0, 8);
+			SCpnt->cmd_len = 0;
+			SCpnt->sense_buffer[0] = 0;
+			SCpnt->sense_buffer[2] = 0;
+
+			{
+				DECLARE_MUTEX_LOCKED(sem);
+				/* Mark as really busy again */
+				SCpnt->request.rq_status = RQ_SCSI_BUSY;
+				SCpnt->request.sem = &sem;
+				scsi_do_cmd(SCpnt,
+					    (void *) cmd, (void *) buffer,
+					    512, sd_init_done, SD_TIMEOUT,
+					    MAX_RETRIES);
+				spin_unlock_irq(&io_request_lock);
+				down(&sem);
+				spin_lock_irq(&io_request_lock);
+				SCpnt->request.sem = NULL;
+			}
+
+			the_result = SCpnt->result;
+			retries++;
+			if (the_result == 0
+			    || SCpnt->sense_buffer[2] != UNIT_ATTENTION)
+				break;
+		}
+
+		/* Look for non-removable devices that return NOT_READY.
+		 * Issue command to spin up drive for these cases. */
+		if (the_result && !rscsi_disks[i].device->removable &&
+		    SCpnt->sense_buffer[2] == NOT_READY) {
+			unsigned long time1;
+			if (!spintime) {
+				printk("%s: Spinning up disk...", nbuff);
+				cmd[0] = START_STOP;
+				cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+				cmd[1] |= 1;	/* Return immediately */
+				memset((void *) &cmd[2], 0, 8);
+				cmd[4] = 1;	/* Start spin cycle */
+				SCpnt->cmd_len = 0;
+				SCpnt->sense_buffer[0] = 0;
+				SCpnt->sense_buffer[2] = 0;
+
+				{
+					DECLARE_MUTEX_LOCKED(sem);
+					/* Mark as really busy again */
+					SCpnt->request.rq_status = RQ_SCSI_BUSY;
+					SCpnt->request.sem = &sem;
+					scsi_do_cmd(SCpnt,
+					   (void *) cmd, (void *) buffer,
+					   512, sd_init_done, SD_TIMEOUT,
+						    MAX_RETRIES);
+					spin_unlock_irq(&io_request_lock);
+					down(&sem);
+					spin_lock_irq(&io_request_lock);
+					SCpnt->request.sem = NULL;
+				}
+
+				spintime = jiffies;
+			}
+			time1 = jiffies + HZ;
+			spin_unlock_irq(&io_request_lock);
+			while (jiffies < time1);	/* Wait 1 second for next try */
+			printk(".");
+			spin_lock_irq(&io_request_lock);
+		}
+	} while (the_result && spintime && spintime + 100 * HZ > jiffies);
+	if (spintime) {
+		if (the_result)
+			printk("not responding...\n");
+		else
+			printk("ready\n");
+	}
+	retries = 3;
+	do {
+		cmd[0] = READ_CAPACITY;
 		cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-		memset ((void *) &cmd[2], 0, 8);
+		memset((void *) &cmd[2], 0, 8);
+		memset((void *) buffer, 0, 8);
 		SCpnt->cmd_len = 0;
 		SCpnt->sense_buffer[0] = 0;
 		SCpnt->sense_buffer[2] = 0;
 
 		{
-		    DECLARE_MUTEX_LOCKED(sem);
-		    /* Mark as really busy again */
-		    SCpnt->request.rq_status = RQ_SCSI_BUSY;
-		    SCpnt->request.sem = &sem;
-		    scsi_do_cmd (SCpnt,
-				 (void *) cmd, (void *) buffer,
-				 512, sd_init_done,  SD_TIMEOUT,
-				 MAX_RETRIES);
-		    spin_unlock_irq(&io_request_lock);
-		    down(&sem);
-		    spin_lock_irq(&io_request_lock);
-                    SCpnt->request.sem = NULL;
-		}
-
-		the_result = SCpnt->result;
-		retries++;
-		if(   the_result == 0
-		   || SCpnt->sense_buffer[2] != UNIT_ATTENTION)
-		    break;
-	    }
-
-	    /* Look for non-removable devices that return NOT_READY.
-	     * Issue command to spin up drive for these cases. */
-	    if(the_result && !rscsi_disks[i].device->removable &&
-	       SCpnt->sense_buffer[2] == NOT_READY) {
-		unsigned long time1;
-		if(!spintime){
-		    printk( "%s: Spinning up disk...", nbuff );
-		    cmd[0] = START_STOP;
-		    cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-		    cmd[1] |= 1;  /* Return immediately */
-		    memset ((void *) &cmd[2], 0, 8);
-		    cmd[4] = 1; /* Start spin cycle */
-		    SCpnt->cmd_len = 0;
-		    SCpnt->sense_buffer[0] = 0;
-		    SCpnt->sense_buffer[2] = 0;
-
-		    {
-		        DECLARE_MUTEX_LOCKED(sem);
+			DECLARE_MUTEX_LOCKED(sem);
 			/* Mark as really busy again */
 			SCpnt->request.rq_status = RQ_SCSI_BUSY;
-		    	SCpnt->request.sem = &sem;
-			scsi_do_cmd (SCpnt,
-				     (void *) cmd, (void *) buffer,
-				     512, sd_init_done,  SD_TIMEOUT,
-				     MAX_RETRIES);
+			SCpnt->request.sem = &sem;
+			scsi_do_cmd(SCpnt,
+				    (void *) cmd, (void *) buffer,
+				    8, sd_init_done, SD_TIMEOUT,
+				    MAX_RETRIES);
 			spin_unlock_irq(&io_request_lock);
-			down(&sem);
+			down(&sem);	/* sleep until it is ready */
 			spin_lock_irq(&io_request_lock);
-                        SCpnt->request.sem = NULL;
-		    }
-
-		    spintime = jiffies;
+			SCpnt->request.sem = NULL;
 		}
 
-		time1 = jiffies + HZ;
-		spin_unlock_irq(&io_request_lock);
-		while(jiffies < time1); /* Wait 1 second for next try */
-		printk( "." );
-		spin_lock_irq(&io_request_lock);
-	    }
-	} while(the_result && spintime && spintime+100*HZ > jiffies);
-	if (spintime) {
-	    if (the_result)
-		printk( "not responding...\n" );
-	    else
-		printk( "ready\n" );
-	}
+		the_result = SCpnt->result;
+		retries--;
 
-    retries = 3;
-    do {
-	cmd[0] = READ_CAPACITY;
-	cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-	memset ((void *) &cmd[2], 0, 8);
-	memset ((void *) buffer, 0, 8);
-	SCpnt->cmd_len = 0;
-	SCpnt->sense_buffer[0] = 0;
-	SCpnt->sense_buffer[2] = 0;
+	} while (the_result && retries);
 
-	{
-            DECLARE_MUTEX_LOCKED(sem);
-	    /* Mark as really busy again */
-	    SCpnt->request.rq_status = RQ_SCSI_BUSY;
-	    SCpnt->request.sem = &sem;
-	    scsi_do_cmd (SCpnt,
-			 (void *) cmd, (void *) buffer,
-			 8, sd_init_done,  SD_TIMEOUT,
-			 MAX_RETRIES);
-	    spin_unlock_irq(&io_request_lock);
-	    down(&sem);	/* sleep until it is ready */
-	    spin_lock_irq(&io_request_lock);
-            SCpnt->request.sem = NULL;
-	}
-
-	the_result = SCpnt->result;
-	retries--;
-
-    } while(the_result && retries);
-
-    /*
-     * The SCSI standard says:
-     * "READ CAPACITY is necessary for self configuring software"
-     *  While not mandatory, support of READ CAPACITY is strongly encouraged.
-     *  We used to die if we couldn't successfully do a READ CAPACITY.
-     *  But, now we go on about our way.  The side effects of this are
-     *
-     *  1. We can't know block size with certainty. I have said "512 bytes
-     *     is it" as this is most common.
-     *
-     *  2. Recovery from when some one attempts to read past the end of the
-     *     raw device will be slower.
-     */
-
-    if (the_result)
-    {
-	printk ("%s : READ CAPACITY failed.\n"
-		"%s : status = %x, message = %02x, host = %d, driver = %02x \n",
-		nbuff, nbuff,
-		status_byte(the_result),
-		msg_byte(the_result),
-		host_byte(the_result),
-		driver_byte(the_result)
-		);
-	if (driver_byte(the_result)  & DRIVER_SENSE)
-	    printk("%s : extended sense code = %1x \n",
-		   nbuff, SCpnt->sense_buffer[2] & 0xf);
-	else
-	    printk("%s : sense not available. \n", nbuff);
-
-	printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
-	       nbuff);
-	rscsi_disks[i].capacity = 0x1fffff;
-	rscsi_disks[i].sector_size = 512;
-
-	/* Set dirty bit for removable devices if not ready - sometimes drives
-	 * will not report this properly. */
-	if(rscsi_disks[i].device->removable &&
-	   SCpnt->sense_buffer[2] == NOT_READY)
-	    rscsi_disks[i].device->changed = 1;
-
-    }
-    else
-    {
 	/*
-	 * FLOPTICAL , if read_capa is ok , drive is assumed to be ready
+	 * The SCSI standard says:
+	 * "READ CAPACITY is necessary for self configuring software"
+	 *  While not mandatory, support of READ CAPACITY is strongly encouraged.
+	 *  We used to die if we couldn't successfully do a READ CAPACITY.
+	 *  But, now we go on about our way.  The side effects of this are
+	 *
+	 *  1. We can't know block size with certainty. I have said "512 bytes
+	 *     is it" as this is most common.
+	 *
+	 *  2. Recovery from when some one attempts to read past the end of the
+	 *     raw device will be slower.
 	 */
-	rscsi_disks[i].ready = 1;
 
-	rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) |
-				       (buffer[1] << 16) |
-				       (buffer[2] << 8) |
-				       buffer[3]);
-
-	rscsi_disks[i].sector_size = (buffer[4] << 24) |
-	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
-
-	if (rscsi_disks[i].sector_size == 0) {
-	  rscsi_disks[i].sector_size = 512;
-	  printk("%s : sector size 0 reported, assuming 512.\n", nbuff);
-	}
+	if (the_result) {
+		printk("%s : READ CAPACITY failed.\n"
+		       "%s : status = %x, message = %02x, host = %d, driver = %02x \n",
+		       nbuff, nbuff,
+		       status_byte(the_result),
+		       msg_byte(the_result),
+		       host_byte(the_result),
+		       driver_byte(the_result)
+		    );
+		if (driver_byte(the_result) & DRIVER_SENSE)
+			printk("%s : extended sense code = %1x \n",
+			       nbuff, SCpnt->sense_buffer[2] & 0xf);
+		else
+			printk("%s : sense not available. \n", nbuff);
 
+		printk("%s : block size assumed to be 512 bytes, disk size 1GB.  \n",
+		       nbuff);
+		rscsi_disks[i].capacity = 0x1fffff;
+		rscsi_disks[i].sector_size = 512;
+
+		/* Set dirty bit for removable devices if not ready - sometimes drives
+		 * will not report this properly. */
+		if (rscsi_disks[i].device->removable &&
+		    SCpnt->sense_buffer[2] == NOT_READY)
+			rscsi_disks[i].device->changed = 1;
 
-	if (rscsi_disks[i].sector_size != 512 &&
-	    rscsi_disks[i].sector_size != 1024 &&
-	    rscsi_disks[i].sector_size != 2048 &&
-	    rscsi_disks[i].sector_size != 4096 &&
-	    rscsi_disks[i].sector_size != 256)
-	{
-	    printk ("%s : unsupported sector size %d.\n",
-		    nbuff, rscsi_disks[i].sector_size);
-	    if(rscsi_disks[i].device->removable){
-		rscsi_disks[i].capacity = 0;
-	    } else {
-		printk ("scsi : deleting disk entry.\n");
-		rscsi_disks[i].device = NULL;
-		sd_template.nr_dev--;
-		SD_GENDISK(i).nr_real--;
-
-                /* Wake up a process waiting for device */
-                wake_up(&SCpnt->device->device_wait);
-                scsi_release_command(SCpnt);
-                SCpnt = NULL;
-                
-		return i;
-	    }
+	} else {
+		/*
+		 * FLOPTICAL , if read_capa is ok , drive is assumed to be ready
+		 */
+		rscsi_disks[i].ready = 1;
+
+		rscsi_disks[i].capacity = 1 + ((buffer[0] << 24) |
+					       (buffer[1] << 16) |
+					       (buffer[2] << 8) |
+					       buffer[3]);
+
+		rscsi_disks[i].sector_size = (buffer[4] << 24) |
+		    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+
+		if (rscsi_disks[i].sector_size == 0) {
+			rscsi_disks[i].sector_size = 512;
+			printk("%s : sector size 0 reported, assuming 512.\n", nbuff);
+		}
+		if (rscsi_disks[i].sector_size != 512 &&
+		    rscsi_disks[i].sector_size != 1024 &&
+		    rscsi_disks[i].sector_size != 2048 &&
+		    rscsi_disks[i].sector_size != 4096 &&
+		    rscsi_disks[i].sector_size != 256) {
+			printk("%s : unsupported sector size %d.\n",
+			       nbuff, rscsi_disks[i].sector_size);
+			if (rscsi_disks[i].device->removable) {
+				rscsi_disks[i].capacity = 0;
+			} else {
+				printk("scsi : deleting disk entry.\n");
+				rscsi_disks[i].device = NULL;
+				sd_template.nr_dev--;
+				SD_GENDISK(i).nr_real--;
+
+				/* Wake up a process waiting for device */
+				wake_up(&SCpnt->device->device_wait);
+				scsi_release_command(SCpnt);
+				SCpnt = NULL;
+
+				return i;
+			}
+		}
+		if (rscsi_disks[i].sector_size == 2048) {
+			int m;
+
+			/*
+			 * We must fix the sd_blocksizes and sd_hardsizes
+			 * to allow us to read the partition tables.
+			 * The disk reading code does not allow for reading
+			 * of partial sectors.
+			 */
+			for (m = i << 4; m < ((i + 1) << 4); m++) {
+				sd_blocksizes[m] = 2048;
+			}
+		} {
+			/*
+			 * The msdos fs needs to know the hardware sector size
+			 * So I have created this table. See ll_rw_blk.c
+			 * Jacques Gelinas (Jacques@solucorp.qc.ca)
+			 */
+			int m, mb;
+			int sz_quot, sz_rem;
+			int hard_sector = rscsi_disks[i].sector_size;
+			/* There are 16 minors allocated for each major device */
+			for (m = i << 4; m < ((i + 1) << 4); m++) {
+				sd_hardsizes[m] = hard_sector;
+			}
+			mb = rscsi_disks[i].capacity / 1024 * hard_sector / 1024;
+			/* sz = div(m/100, 10);  this seems to not be in the libr */
+			m = (mb + 50) / 100;
+			sz_quot = m / 10;
+			sz_rem = m - (10 * sz_quot);
+			printk("SCSI device %s: hdwr sector= %d bytes."
+			       " Sectors= %d [%d MB] [%d.%1d GB]\n",
+			     nbuff, hard_sector, rscsi_disks[i].capacity,
+			       mb, sz_quot, sz_rem);
+		}
+		if (rscsi_disks[i].sector_size == 4096)
+			rscsi_disks[i].capacity <<= 3;
+		if (rscsi_disks[i].sector_size == 2048)
+			rscsi_disks[i].capacity <<= 2;	/* Change into 512 byte sectors */
+		if (rscsi_disks[i].sector_size == 1024)
+			rscsi_disks[i].capacity <<= 1;	/* Change into 512 byte sectors */
+		if (rscsi_disks[i].sector_size == 256)
+			rscsi_disks[i].capacity >>= 1;	/* Change into 512 byte sectors */
 	}
 
-        if( rscsi_disks[i].sector_size == 2048 )
-          {
-            int m;
-
-            /*
-             * We must fix the sd_blocksizes and sd_hardsizes
-             * to allow us to read the partition tables.
-             * The disk reading code does not allow for reading
-             * of partial sectors.
-             */
-            for (m=i<<4; m<((i+1)<<4); m++)
-              {
-                sd_blocksizes[m] = 2048;
-              }
-          }
-    {
-	/*
-	 * The msdos fs needs to know the hardware sector size
-	 * So I have created this table. See ll_rw_blk.c
-	 * Jacques Gelinas (Jacques@solucorp.qc.ca)
-	 */
-	int m, mb;
-        int sz_quot, sz_rem;
-	int hard_sector = rscsi_disks[i].sector_size;
-	/* There are 16 minors allocated for each major device */
-	for (m=i<<4; m<((i+1)<<4); m++){
-	    sd_hardsizes[m] = hard_sector;
-	}
-        mb = rscsi_disks[i].capacity / 1024 * hard_sector / 1024;
-        /* sz = div(m/100, 10);  this seems to not be in the libr */
-        m = (mb + 50) / 100;
-        sz_quot = m / 10;
-        sz_rem = m - (10 * sz_quot);
-	printk ("SCSI device %s: hdwr sector= %d bytes."
-               " Sectors= %d [%d MB] [%d.%1d GB]\n",
-		nbuff, hard_sector, rscsi_disks[i].capacity,
-                mb, sz_quot, sz_rem);
-    }
-	if(rscsi_disks[i].sector_size == 4096)
-	    rscsi_disks[i].capacity <<= 3;
-	if(rscsi_disks[i].sector_size == 2048)
-	    rscsi_disks[i].capacity <<= 2;  /* Change into 512 byte sectors */
-	if(rscsi_disks[i].sector_size == 1024)
-	    rscsi_disks[i].capacity <<= 1;  /* Change into 512 byte sectors */
-	if(rscsi_disks[i].sector_size == 256)
-	    rscsi_disks[i].capacity >>= 1;  /* Change into 512 byte sectors */
-    }
-
-
-    /*
-     * Unless otherwise specified, this is not write protected.
-     */
-    rscsi_disks[i].write_prot = 0;
-    if ( rscsi_disks[i].device->removable && rscsi_disks[i].ready ) {
-	/* FLOPTICAL */
 
 	/*
-	 *	for removable scsi disk ( FLOPTICAL ) we have to recognise
-	 * the Write Protect Flag. This flag is kept in the Scsi_Disk struct
-	 * and tested at open !
-	 * Daniel Roche ( dan@lectra.fr )
+	 * Unless otherwise specified, this is not write protected.
 	 */
+	rscsi_disks[i].write_prot = 0;
+	if (rscsi_disks[i].device->removable && rscsi_disks[i].ready) {
+		/* FLOPTICAL */
 
-	memset ((void *) &cmd[0], 0, 8);
-	cmd[0] = MODE_SENSE;
-	cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
-	cmd[2] = 1;	 /* page code 1 ?? */
-	cmd[4] = 12;
-	SCpnt->cmd_len = 0;
-	SCpnt->sense_buffer[0] = 0;
-	SCpnt->sense_buffer[2] = 0;
+		/*
+		 *    for removable scsi disk ( FLOPTICAL ) we have to recognise
+		 * the Write Protect Flag. This flag is kept in the Scsi_Disk struct
+		 * and tested at open !
+		 * Daniel Roche ( dan@lectra.fr )
+		 */
 
-	/* same code as READCAPA !! */
-	{
-            DECLARE_MUTEX_LOCKED(sem);
-	    SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Mark as really busy again */
-	    SCpnt->request.sem = &sem;
-	    scsi_do_cmd (SCpnt,
-			 (void *) cmd, (void *) buffer,
-			 512, sd_init_done,  SD_TIMEOUT,
-			 MAX_RETRIES);
-	    spin_unlock_irq(&io_request_lock);
-	    down(&sem);
-	    spin_lock_irq(&io_request_lock);
-            SCpnt->request.sem = NULL;
-	}
-
-	the_result = SCpnt->result;
-
-	if ( the_result ) {
-	    printk ("%s: test WP failed, assume Write Protected\n",nbuff);
-	    rscsi_disks[i].write_prot = 1;
-	} else {
-	    rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
-	    printk ("%s: Write Protect is %s\n",nbuff,
-	            rscsi_disks[i].write_prot ? "on" : "off");
-	}
-
-    }	/* check for write protect */
-
-    /* Wake up a process waiting for device */
-    wake_up(&SCpnt->device->device_wait);
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    rscsi_disks[i].ten = 1;
-    rscsi_disks[i].remap = 1;
-    scsi_free(buffer, 512);
-    spin_unlock_irq(&io_request_lock);
-    return i;
+		memset((void *) &cmd[0], 0, 8);
+		cmd[0] = MODE_SENSE;
+		cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+		cmd[2] = 1;	/* page code 1 ?? */
+		cmd[4] = 12;
+		SCpnt->cmd_len = 0;
+		SCpnt->sense_buffer[0] = 0;
+		SCpnt->sense_buffer[2] = 0;
+
+		/* same code as READCAPA !! */
+		{
+			DECLARE_MUTEX_LOCKED(sem);
+			SCpnt->request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy again */
+			SCpnt->request.sem = &sem;
+			scsi_do_cmd(SCpnt,
+				    (void *) cmd, (void *) buffer,
+				    512, sd_init_done, SD_TIMEOUT,
+				    MAX_RETRIES);
+			spin_unlock_irq(&io_request_lock);
+			down(&sem);
+			spin_lock_irq(&io_request_lock);
+			SCpnt->request.sem = NULL;
+		}
+
+		the_result = SCpnt->result;
+
+		if (the_result) {
+			printk("%s: test WP failed, assume Write Protected\n", nbuff);
+			rscsi_disks[i].write_prot = 1;
+		} else {
+			rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
+			printk("%s: Write Protect is %s\n", nbuff,
+			       rscsi_disks[i].write_prot ? "on" : "off");
+		}
+
+	}			/* check for write protect */
+	/* Wake up a process waiting for device */
+	wake_up(&SCpnt->device->device_wait);
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	rscsi_disks[i].ten = 1;
+	rscsi_disks[i].remap = 1;
+	scsi_free(buffer, 512);
+	spin_unlock_irq(&io_request_lock);
+	return i;
 }
 
 /*
@@ -1492,171 +1449,170 @@
 
 static int sd_init()
 {
-    int i;
+	int i;
 
-    if (sd_template.dev_noticed == 0) return 0;
+	if (sd_template.dev_noticed == 0)
+		return 0;
 
-    if (!rscsi_disks)
-        sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
+	if (!rscsi_disks)
+		sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
 
-    if(sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR )
-	sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR;
+	if (sd_template.dev_max > N_SD_MAJORS * SCSI_DISKS_PER_MAJOR)
+		sd_template.dev_max = N_SD_MAJORS * SCSI_DISKS_PER_MAJOR;
 
-    if(!sd_registered) {
-	for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
-	    if (register_blkdev(SD_MAJOR(i),"sd",&sd_fops)) {
-		printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i));
-		return 1;
-	    }
+	if (!sd_registered) {
+		for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
+			if (register_blkdev(SD_MAJOR(i), "sd", &sd_fops)) {
+				printk("Unable to get major %d for SCSI disk\n", SD_MAJOR(i));
+				return 1;
+			}
+		}
+		sd_registered++;
 	}
-	sd_registered++;
-    }
-
-    /* We do not support attaching loadable devices yet. */
-    if(rscsi_disks) return 0;
-
-    rscsi_disks = (Scsi_Disk *)
-	scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
-    memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
-    
-  /* for every (necessary) major: */
-    sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
-    memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
-
-    sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
-    sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
-
-    for(i=0; i < sd_template.dev_max << 4; i++) {
-	sd_blocksizes[i] = 1024;
-	sd_hardsizes[i] = 512;
-    }
- 
-    for (i=0; i < N_USED_SD_MAJORS; i++) {
-	blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4);
-	hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4);
-    }
-    sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
-					       sizeof(struct hd_struct),
-					       GFP_ATOMIC);
-
-    if (N_USED_SD_MAJORS > 1)
-    	sd_gendisks = (struct gendisk *)
-    	    kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
-    for (i=0; i < N_USED_SD_MAJORS; i++) {
-	sd_gendisks[i].major = SD_MAJOR(i);
-	sd_gendisks[i].major_name = "sd";
-	sd_gendisks[i].minor_shift = 4;
-	sd_gendisks[i].max_p = 1 << 4;
-	sd_gendisks[i].max_nr = SCSI_DISKS_PER_MAJOR;
-	sd_gendisks[i].init = sd_geninit;
-	sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4);
-	sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4);
-	sd_gendisks[i].nr_real = 0;
-	sd_gendisks[i].next = sd_gendisks + i + 1;
-	sd_gendisks[i].real_devices =
-		 (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
-    }
-    
-    LAST_SD_GENDISK.max_nr =
-    	(sd_template.dev_max -1 ) % SCSI_DISKS_PER_MAJOR + 1;
-    LAST_SD_GENDISK.next = NULL;
-    return 0;
+	/* We do not support attaching loadable devices yet. */
+	if (rscsi_disks)
+		return 0;
+
+	rscsi_disks = (Scsi_Disk *)
+	    scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
+	memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
+
+	/* for every (necessary) major: */
+	sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+	memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
+
+	sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+	sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) * sizeof(int), GFP_ATOMIC);
+
+	for (i = 0; i < sd_template.dev_max << 4; i++) {
+		sd_blocksizes[i] = 1024;
+		sd_hardsizes[i] = 512;
+	}
+
+	for (i = 0; i < N_USED_SD_MAJORS; i++) {
+		blksize_size[SD_MAJOR(i)] = sd_blocksizes + i * (SCSI_DISKS_PER_MAJOR << 4);
+		hardsect_size[SD_MAJOR(i)] = sd_hardsizes + i * (SCSI_DISKS_PER_MAJOR << 4);
+	}
+	sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
+						sizeof(struct hd_struct),
+						   GFP_ATOMIC);
+
+	if (N_USED_SD_MAJORS > 1)
+		sd_gendisks = (struct gendisk *)
+		    kmalloc(N_USED_SD_MAJORS * sizeof(struct gendisk), GFP_ATOMIC);
+	for (i = 0; i < N_USED_SD_MAJORS; i++) {
+		sd_gendisks[i].major = SD_MAJOR(i);
+		sd_gendisks[i].major_name = "sd";
+		sd_gendisks[i].minor_shift = 4;
+		sd_gendisks[i].max_p = 1 << 4;
+		sd_gendisks[i].max_nr = SCSI_DISKS_PER_MAJOR;
+		sd_gendisks[i].init = sd_geninit;
+		sd_gendisks[i].part = sd + (i * SCSI_DISKS_PER_MAJOR << 4);
+		sd_gendisks[i].sizes = sd_sizes + (i * SCSI_DISKS_PER_MAJOR << 4);
+		sd_gendisks[i].nr_real = 0;
+		sd_gendisks[i].next = sd_gendisks + i + 1;
+		sd_gendisks[i].real_devices =
+		    (void *) (rscsi_disks + i * SCSI_DISKS_PER_MAJOR);
+	}
+
+	LAST_SD_GENDISK.max_nr =
+	    (sd_template.dev_max - 1) % SCSI_DISKS_PER_MAJOR + 1;
+	LAST_SD_GENDISK.next = NULL;
+	return 0;
 }
 
 /*
  * sd_get_queue() returns the queue which corresponds to a given device.
  */
-static struct request **sd_get_queue (kdev_t dev)
+static struct request **sd_get_queue(kdev_t dev)
 {
 	return &blk_dev[MAJOR_NR].current_request;
 }
-
 static void sd_finish()
 {
-    struct gendisk *gendisk;
-    int i;
+	struct gendisk *gendisk;
+	int i;
 
-    for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
-        /* FIXME: After 2.2 we should implement multiple sd queues */
-        blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST;
-        if (i) blk_dev[SD_MAJOR(i)].queue = sd_get_queue;
-    }
-
-    for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
-      if (gendisk == sd_gendisks)
-	break;
-    if (gendisk == NULL)
-      {
-	LAST_SD_GENDISK.next = gendisk_head;
-	gendisk_head = sd_gendisks;
-      }
-
-    for (i = 0; i < sd_template.dev_max; ++i)
-	if (!rscsi_disks[i].capacity &&
-	    rscsi_disks[i].device)
-	{
-	    if (MODULE_FLAG
-		&& !rscsi_disks[i].has_part_table) {
-		sd_sizes[i << 4] = rscsi_disks[i].capacity;
-		/* revalidate does sd_init_onedisk via MAYBE_REINIT*/
-		revalidate_scsidisk(MKDEV_SD(i), 0);
-	    }
-	    else
-	    	i=sd_init_onedisk(i);
-	    rscsi_disks[i].has_part_table = 1;
-	}
-
-    /* If our host adapter is capable of scatter-gather, then we increase
-     * the read-ahead to 60 blocks (120 sectors).  If not, we use
-     * a two block (4 sector) read ahead. We can only respect this with the
-     * granularity of every 16 disks (one device major).
-     */
-    for (i=0; i < N_USED_SD_MAJORS; i++) {
-        read_ahead[SD_MAJOR(i)] =
-            (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device
-          && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize)
-            ? 120  /* 120 sector read-ahead */
-            : 4;   /* 4 sector read-ahead */
-    }
+	for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
+		/* FIXME: After 2.2 we should implement multiple sd queues */
+		blk_dev[SD_MAJOR(i)].request_fn = DEVICE_REQUEST;
+		if (i)
+			blk_dev[SD_MAJOR(i)].queue = sd_get_queue;
+	}
+	for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
+		if (gendisk == sd_gendisks)
+			break;
+	if (gendisk == NULL) {
+		LAST_SD_GENDISK.next = gendisk_head;
+		gendisk_head = sd_gendisks;
+	}
+	for (i = 0; i < sd_template.dev_max; ++i)
+		if (!rscsi_disks[i].capacity &&
+		    rscsi_disks[i].device) {
+			if (MODULE_FLAG
+			    && !rscsi_disks[i].has_part_table) {
+				sd_sizes[i << 4] = rscsi_disks[i].capacity;
+				/* revalidate does sd_init_onedisk via MAYBE_REINIT */
+				revalidate_scsidisk(MKDEV_SD(i), 0);
+			} else
+				i = sd_init_onedisk(i);
+			rscsi_disks[i].has_part_table = 1;
+		}
+	/* If our host adapter is capable of scatter-gather, then we increase
+	 * the read-ahead to 60 blocks (120 sectors).  If not, we use
+	 * a two block (4 sector) read ahead. We can only respect this with the
+	 * granularity of every 16 disks (one device major).
+	 */
+	for (i = 0; i < N_USED_SD_MAJORS; i++) {
+		read_ahead[SD_MAJOR(i)] =
+		    (rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device
+		     && rscsi_disks[i * SCSI_DISKS_PER_MAJOR].device->host->sg_tablesize)
+		    ? 120	/* 120 sector read-ahead */
+		    : 4;	/* 4 sector read-ahead */
+	}
 
-    return;
+	return;
 }
 
-static int sd_detect(Scsi_Device * SDp){
-    char nbuff[6];
-    if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-
-    sd_devname(sd_template.dev_noticed++, nbuff);
-    printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
-           SDp->removable ? "removable " : "",
-	   nbuff,
-	   SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+static int sd_detect(Scsi_Device * SDp)
+{
+	char nbuff[6];
+	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
+		return 0;
+
+	sd_devname(sd_template.dev_noticed++, nbuff);
+	printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
+	       SDp->removable ? "removable " : "",
+	       nbuff,
+	       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 
-    return 1;
+	return 1;
 }
+static int sd_attach(Scsi_Device * SDp)
+{
+	Scsi_Disk *dpnt;
+	int i;
 
-static int sd_attach(Scsi_Device * SDp){
-    Scsi_Disk * dpnt;
-    int i;
-
-    if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
+	if (SDp->type != TYPE_DISK && SDp->type != TYPE_MOD)
+		return 0;
 
-    if(sd_template.nr_dev >= sd_template.dev_max) {
-	SDp->attached--;
-	return 1;
-    }
-
-    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
-	if(!dpnt->device) break;
+	if (sd_template.nr_dev >= sd_template.dev_max) {
+		SDp->attached--;
+		return 1;
+	}
+	for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
+		if (!dpnt->device)
+			break;
 
-    if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
+	if (i >= sd_template.dev_max)
+		panic("scsi_devices corrupt (sd)");
 
-    SDp->scsi_request_fn = do_sd_request;
-    rscsi_disks[i].device = SDp;
-    rscsi_disks[i].has_part_table = 0;
-    sd_template.nr_dev++;
-    SD_GENDISK(i).nr_real++;
-    return 0;
+	SDp->scsi_request_fn = do_sd_request;
+	rscsi_disks[i].device = SDp;
+	rscsi_disks[i].has_part_table = 0;
+	sd_template.nr_dev++;
+	SD_GENDISK(i).nr_real++;
+	return 0;
 }
 
 #define DEVICE_BUSY rscsi_disks[target].device->busy
@@ -1671,160 +1627,160 @@
  * usage == 1 (we need an open channel to use an ioctl :-), so this
  * is our limit.
  */
-int revalidate_scsidisk(kdev_t dev, int maxusage) {
-    int target;
-    int max_p;
-    int start;
-    int i;
-
-    target =  DEVICE_NR(dev);
-
-    if (DEVICE_BUSY || USAGE > maxusage) {
-	printk("Device busy for revalidation (usage=%d)\n", USAGE);
-	return -EBUSY;
-    }
-    DEVICE_BUSY = 1;
-
-    max_p = sd_gendisks->max_p;
-    start = target << sd_gendisks->minor_shift;
-
-    for (i=max_p - 1; i >=0 ; i--) {
-	int index = start+i;
-	kdev_t devi = MKDEV_SD_PARTITION(index);
-        struct super_block *sb = get_super(devi);
-	sync_dev(devi);
-	if (sb) invalidate_inodes(sb);
-	invalidate_buffers(devi);
-	sd_gendisks->part[index].start_sect = 0;
-	sd_gendisks->part[index].nr_sects = 0;
-        /*
-         * Reset the blocksize for everything so that we can read
-         * the partition table.  Technically we will determine the
-         * correct block size when we revalidate, but we do this just
-         * to make sure that everything remains consistent.
-         */
-        sd_blocksizes[index] = 1024;
-        if( rscsi_disks[target].sector_size == 2048 )
-          sd_blocksizes[index] = 2048;
-        else
-          sd_blocksizes[index] = 1024;
-    }
-
-#ifdef MAYBE_REINIT
-    MAYBE_REINIT;
-#endif
+int revalidate_scsidisk(kdev_t dev, int maxusage)
+{
+	int target;
+	int max_p;
+	int start;
+	int i;
 
-    sd_gendisks->part[start].nr_sects = CAPACITY;
-    resetup_one_dev(&SD_GENDISK(target),
-		    target % SCSI_DISKS_PER_MAJOR);
+	target = DEVICE_NR(dev);
 
-    DEVICE_BUSY = 0;
-    return 0;
-}
-
-static int fop_revalidate_scsidisk(kdev_t dev){
-    return revalidate_scsidisk(dev, 0);
-}
+	if (DEVICE_BUSY || USAGE > maxusage) {
+		printk("Device busy for revalidation (usage=%d)\n", USAGE);
+		return -EBUSY;
+	}
+	DEVICE_BUSY = 1;
 
+	max_p = sd_gendisks->max_p;
+	start = target << sd_gendisks->minor_shift;
 
-static void sd_detach(Scsi_Device * SDp)
-{
-    Scsi_Disk * dpnt;
-    int i, j;
-    int max_p;
-    int start;
-
-    for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
-	if(dpnt->device == SDp) {
-
-	    /* If we are disconnecting a disk driver, sync and invalidate
-	     * everything */
-	    max_p = sd_gendisk.max_p;
-	    start = i << sd_gendisk.minor_shift;
-
-	    for (j=max_p - 1; j >=0 ; j--) {
-		int index = start+j;
+	for (i = max_p - 1; i >= 0; i--) {
+		int index = start + i;
 		kdev_t devi = MKDEV_SD_PARTITION(index);
-                struct super_block *sb = get_super(devi);
+		struct super_block *sb = get_super(devi);
 		sync_dev(devi);
-		if (sb) invalidate_inodes(sb);
+		if (sb)
+			invalidate_inodes(sb);
 		invalidate_buffers(devi);
 		sd_gendisks->part[index].start_sect = 0;
 		sd_gendisks->part[index].nr_sects = 0;
-		sd_sizes[index] = 0;
-	    }
-
-	    dpnt->has_part_table = 0;
-	    dpnt->device = NULL;
-	    dpnt->capacity = 0;
-	    SDp->attached--;
-	    sd_template.dev_noticed--;
-	    sd_template.nr_dev--;
-	    SD_GENDISK(i).nr_real--;
-	    return;
+		/*
+		 * Reset the blocksize for everything so that we can read
+		 * the partition table.  Technically we will determine the
+		 * correct block size when we revalidate, but we do this just
+		 * to make sure that everything remains consistent.
+		 */
+		sd_blocksizes[index] = 1024;
+		if (rscsi_disks[target].sector_size == 2048)
+			sd_blocksizes[index] = 2048;
+		else
+			sd_blocksizes[index] = 1024;
 	}
-    return;
+
+#ifdef MAYBE_REINIT
+	MAYBE_REINIT;
+#endif
+
+	sd_gendisks->part[start].nr_sects = CAPACITY;
+	resetup_one_dev(&SD_GENDISK(target),
+			target % SCSI_DISKS_PER_MAJOR);
+
+	DEVICE_BUSY = 0;
+	return 0;
+}
+
+static int fop_revalidate_scsidisk(kdev_t dev)
+{
+	return revalidate_scsidisk(dev, 0);
+}
+static void sd_detach(Scsi_Device * SDp)
+{
+	Scsi_Disk *dpnt;
+	int i, j;
+	int max_p;
+	int start;
+
+	for (dpnt = rscsi_disks, i = 0; i < sd_template.dev_max; i++, dpnt++)
+		if (dpnt->device == SDp) {
+
+			/* If we are disconnecting a disk driver, sync and invalidate
+			 * everything */
+			max_p = sd_gendisk.max_p;
+			start = i << sd_gendisk.minor_shift;
+
+			for (j = max_p - 1; j >= 0; j--) {
+				int index = start + j;
+				kdev_t devi = MKDEV_SD_PARTITION(index);
+				struct super_block *sb = get_super(devi);
+				sync_dev(devi);
+				if (sb)
+					invalidate_inodes(sb);
+				invalidate_buffers(devi);
+				sd_gendisks->part[index].start_sect = 0;
+				sd_gendisks->part[index].nr_sects = 0;
+				sd_sizes[index] = 0;
+			}
+			dpnt->has_part_table = 0;
+			dpnt->device = NULL;
+			dpnt->capacity = 0;
+			SDp->attached--;
+			sd_template.dev_noticed--;
+			sd_template.nr_dev--;
+			SD_GENDISK(i).nr_real--;
+			return;
+		}
+	return;
 }
 
 #ifdef MODULE
 
-int init_module(void) {
-    sd_template.module = &__this_module;
-    return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
+int init_module(void)
+{
+	sd_template.module = &__this_module;
+	return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
 }
-
-void cleanup_module( void)
+void cleanup_module(void)
 {
-    struct gendisk ** prev_sdgd_link;
-    struct gendisk * sdgd;
-    int i;
-    int removed = 0;
-
-    scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
-
-    for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) 
-	unregister_blkdev(SD_MAJOR(i),"sd");
-    
-    sd_registered--;
-    if( rscsi_disks != NULL )
-    {
-	scsi_init_free((char *) rscsi_disks, 
-			sd_template.dev_max * sizeof(Scsi_Disk));
-	scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int));
-	scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int));
-	scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
-	scsi_init_free((char *) sd,
-		       (sd_template.dev_max << 4) * sizeof(struct hd_struct));
+	struct gendisk **prev_sdgd_link;
+	struct gendisk *sdgd;
+	int i;
+	int removed = 0;
 
-	/*
-	 * Now remove sd_gendisks from the linked list
-	 */
-	prev_sdgd_link = &gendisk_head;
-	while ((sdgd = *prev_sdgd_link) != NULL) {
-	    if (sdgd >= sd_gendisks && sdgd <= &LAST_SD_GENDISK) {
-		removed++;
-		*prev_sdgd_link = sdgd->next;
-		continue;
-	    }
-	    prev_sdgd_link = &sdgd->next;
-	}
-
-	if (removed != N_USED_SD_MAJORS)
-	    printk("%s %d sd_gendisks in disk chain",
-	    	removed > N_USED_SD_MAJORS ? "total" : "just", removed);
-	
-    }
-
-    for (i=0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
-        blk_dev[SD_MAJOR(i)].request_fn = NULL;
-        blk_size[SD_MAJOR(i)] = NULL;
-        hardsect_size[SD_MAJOR(i)] = NULL;
-        read_ahead[SD_MAJOR(i)] = 0;
-    }
-    sd_template.dev_max = 0;
-    if (sd_gendisks != &sd_gendisk) kfree(sd_gendisks);
+	scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
+
+	for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++)
+		unregister_blkdev(SD_MAJOR(i), "sd");
+
+	sd_registered--;
+	if (rscsi_disks != NULL) {
+		scsi_init_free((char *) rscsi_disks,
+			       sd_template.dev_max * sizeof(Scsi_Disk));
+		scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int));
+		scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int));
+		scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
+		scsi_init_free((char *) sd,
+		  (sd_template.dev_max << 4) * sizeof(struct hd_struct));
+
+		/*
+		 * Now remove sd_gendisks from the linked list
+		 */
+		prev_sdgd_link = &gendisk_head;
+		while ((sdgd = *prev_sdgd_link) != NULL) {
+			if (sdgd >= sd_gendisks && sdgd <= &LAST_SD_GENDISK) {
+				removed++;
+				*prev_sdgd_link = sdgd->next;
+				continue;
+			}
+			prev_sdgd_link = &sdgd->next;
+		}
+
+		if (removed != N_USED_SD_MAJORS)
+			printk("%s %d sd_gendisks in disk chain",
+			       removed > N_USED_SD_MAJORS ? "total" : "just", removed);
+
+	}
+	for (i = 0; i <= (sd_template.dev_max - 1) / SCSI_DISKS_PER_MAJOR; i++) {
+		blk_dev[SD_MAJOR(i)].request_fn = NULL;
+		blk_size[SD_MAJOR(i)] = NULL;
+		hardsect_size[SD_MAJOR(i)] = NULL;
+		read_ahead[SD_MAJOR(i)] = 0;
+	}
+	sd_template.dev_max = 0;
+	if (sd_gendisks != &sd_gendisk)
+		kfree(sd_gendisks);
 }
-#endif /* MODULE */
+#endif				/* MODULE */
 
 /*
  * Overrides for Emacs so that we almost follow Linus's tabbing style.
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h
--- v2.3.16/linux/drivers/scsi/sd.h	Wed Aug 18 16:44:26 1999
+++ linux/drivers/scsi/sd.h	Tue Sep  7 11:50:56 1999
@@ -1,19 +1,19 @@
 /*
- *	sd.h Copyright (C) 1992 Drew Eckhardt 
- *	SCSI disk driver header file by
- *		Drew Eckhardt 
+ *    sd.h Copyright (C) 1992 Drew Eckhardt 
+ *      SCSI disk driver header file by
+ *              Drew Eckhardt 
  *
- *	<drew@colorado.edu>
+ *      <drew@colorado.edu>
  *
- *	 Modified by Eric Youngdale eric@aib.com to
- *	 add scatter-gather, multiple outstanding request, and other
- *	 enhancements.
+ *       Modified by Eric Youngdale eric@aib.com to
+ *       add scatter-gather, multiple outstanding request, and other
+ *       enhancements.
  */
 #ifndef _SD_H
 #define _SD_H
 /*
-    $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $
-*/
+   $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $
+ */
 
 #ifndef _SCSI_H
 #include "scsi.h"
@@ -23,22 +23,22 @@
 #include <linux/genhd.h>
 #endif
 
-extern struct hd_struct * sd;
+extern struct hd_struct *sd;
 
 typedef struct scsi_disk {
-    unsigned capacity;		    /* size in blocks */
-    unsigned sector_size;	    /* size in bytes */
-    Scsi_Device	 *device;	    
-    unsigned char ready;	    /* flag ready for FLOPTICAL */
-    unsigned char write_prot;	    /* flag write_protect for rmvable dev */
-    unsigned char sector_bit_size;  /* sector_size = 2 to the  bit size power */
-    unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
-    unsigned ten:1;		    /* support ten byte read / write */
-    unsigned remap:1;		    /* support remapping  */
-    unsigned has_part_table:1;	    /* has partition table */
+	unsigned capacity;	/* size in blocks */
+	unsigned sector_size;	/* size in bytes */
+	Scsi_Device *device;
+	unsigned char ready;	/* flag ready for FLOPTICAL */
+	unsigned char write_prot;	/* flag write_protect for rmvable dev */
+	unsigned char sector_bit_size;	/* sector_size = 2 to the  bit size power */
+	unsigned char sector_bit_shift;		/* power of 2 sectors per FS block */
+	unsigned ten:1;		/* support ten byte read / write */
+	unsigned remap:1;	/* support remapping  */
+	unsigned has_part_table:1;	/* has partition table */
 } Scsi_Disk;
 
-extern Scsi_Disk * rscsi_disks;
+extern Scsi_Disk *rscsi_disks;
 
 extern int revalidate_scsidisk(kdev_t dev, int maxusage);
 
@@ -67,4 +67,3 @@
  * tab-width: 8
  * End:
  */
-
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.3.16/linux/drivers/scsi/sr.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/sr.c	Sat Sep  4 10:48:46 1999
@@ -1,27 +1,27 @@
 /*
  *  sr.c Copyright (C) 1992 David Giller
- *	     Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *           Copyright (C) 1993, 1994, 1995 Eric Youngdale
  *
  *  adapted from:
- *	sd.c Copyright (C) 1992 Drew Eckhardt
- *	Linux scsi disk driver by
- *		Drew Eckhardt <drew@colorado.edu>
+ *      sd.c Copyright (C) 1992 Drew Eckhardt
+ *      Linux scsi disk driver by
+ *              Drew Eckhardt <drew@colorado.edu>
  *
  *      Modified by Eric Youngdale ericy@cais.com to
  *      add scatter-gather, multiple outstanding request, and other
  *      enhancements.
  *
- *	    Modified by Eric Youngdale eric@aib.com to support loadable
- *	    low-level scsi drivers.
+ *          Modified by Eric Youngdale eric@aib.com to support loadable
+ *          low-level scsi drivers.
  *
- *	 Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to
- *	 provide auto-eject.
+ *       Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to
+ *       provide auto-eject.
  *
  *          Modified by Gerd Knorr <kraxel@cs.tu-berlin.de> to support the
  *          generic cdrom interface
  *
- *	 Modified by Jens Axboe <axboe@image.dk> - Uniform sr_packet()
- *	 interface, capabilities probe additions, ioctl cleanups, etc.
+ *       Modified by Jens Axboe <axboe@image.dk> - Uniform sr_packet()
+ *       interface, capabilities probe additions, ioctl cleanups, etc.
  *
  */
 
@@ -44,13 +44,13 @@
 #include "scsi.h"
 #include "hosts.h"
 #include "sr.h"
-#include <scsi/scsi_ioctl.h>   /* For the door lock/unlock commands */
+#include <scsi/scsi_ioctl.h>	/* For the door lock/unlock commands */
 #include "constants.h"
 
-MODULE_PARM(xa_test,"i"); /* see sr_ioctl.c */
+MODULE_PARM(xa_test, "i");	/* see sr_ioctl.c */
 
-#define MAX_RETRIES 3
-#define SR_TIMEOUT (30 * HZ)
+#define MAX_RETRIES	3
+#define SR_TIMEOUT	(30 * HZ)
 
 static int sr_init(void);
 static void sr_finish(void);
@@ -58,55 +58,58 @@
 static int sr_detect(Scsi_Device *);
 static void sr_detach(Scsi_Device *);
 
-struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM,
-                                           SCSI_CDROM_MAJOR, 0, 0, 0, 1,
-                                           sr_detect, sr_init,
-                                           sr_finish, sr_attach, sr_detach};
+struct Scsi_Device_Template sr_template = {
+	NULL, "cdrom", "sr", NULL, TYPE_ROM,
+	SCSI_CDROM_MAJOR, 0, 0, 0, 1,
+	sr_detect, sr_init,
+	sr_finish, sr_attach, sr_detach
+};
 
-Scsi_CD * scsi_CDs = NULL;
-static int * sr_sizes = NULL;
+Scsi_CD *scsi_CDs = NULL;
+static int *sr_sizes = NULL;
 
-static int * sr_blocksizes = NULL;
+static int *sr_blocksizes = NULL;
 
-static int sr_open(struct cdrom_device_info*, int);
+static int sr_open(struct cdrom_device_info *, int);
 void get_sectorsize(int);
 void get_capabilities(int);
 
-void requeue_sr_request (Scsi_Cmnd * SCpnt);
-static int sr_media_change(struct cdrom_device_info*, int);
+void requeue_sr_request(Scsi_Cmnd * SCpnt);
+static int sr_media_change(struct cdrom_device_info *, int);
 static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
 
 static void sr_release(struct cdrom_device_info *cdi)
 {
 	if (scsi_CDs[MINOR(cdi->dev)].sector_size > 2048)
-		sr_set_blocklength(MINOR(cdi->dev),2048);
+		sr_set_blocklength(MINOR(cdi->dev), 2048);
 	sync_dev(cdi->dev);
 	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
 	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
-	if(sr_template.module)
-        	__MOD_DEC_USE_COUNT(sr_template.module);
+	if (sr_template.module)
+		__MOD_DEC_USE_COUNT(sr_template.module);
 }
 
-static struct cdrom_device_ops sr_dops = {
-        sr_open,                      /* open */
-        sr_release,                   /* release */
-        sr_drive_status,              /* drive status */
-        sr_media_change,              /* media changed */
-        sr_tray_move,                 /* tray move */
-        sr_lock_door,                 /* lock door */
-        sr_select_speed,              /* select speed */
-        NULL,                         /* select disc */
-        sr_get_last_session,          /* get last session */
-        sr_get_mcn,                   /* get universal product code */
-        sr_reset,                     /* hard reset */
-        sr_audio_ioctl,               /* audio ioctl */
-        sr_dev_ioctl,                 /* device-specific ioctl */
-        CDC_CLOSE_TRAY | CDC_OPEN_TRAY| CDC_LOCK | CDC_SELECT_SPEED |
-        CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
-        CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW |
+static struct cdrom_device_ops sr_dops =
+{
+	sr_open,		/* open */
+	sr_release,		/* release */
+	sr_drive_status,	/* drive status */
+	sr_media_change,	/* media changed */
+	sr_tray_move,		/* tray move */
+	sr_lock_door,		/* lock door */
+	sr_select_speed,	/* select speed */
+	NULL,			/* select disc */
+	sr_get_last_session,	/* get last session */
+	sr_get_mcn,		/* get universal product code */
+	sr_reset,		/* hard reset */
+	sr_audio_ioctl,		/* audio ioctl */
+	sr_dev_ioctl,		/* device-specific ioctl */
+	CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED |
+	CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO |
+	CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW |
 	CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET,
-        0,
+	0,
 	sr_packet
 };
 
@@ -120,48 +123,47 @@
  * an inode for that to work, and we do not always have one.
  */
 
-int sr_media_change(struct cdrom_device_info *cdi, int slot){
+int sr_media_change(struct cdrom_device_info *cdi, int slot)
+{
 	int retval;
 
-        if (CDSL_CURRENT != slot) {
-                /* no changer support */
-                return -EINVAL;
-        }
-
+	if (CDSL_CURRENT != slot) {
+		/* no changer support */
+		return -EINVAL;
+	}
 	retval = scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
-                            SCSI_IOCTL_TEST_UNIT_READY, 0);
+			    SCSI_IOCTL_TEST_UNIT_READY, 0);
 
-	if(retval)
-        {
-                /* Unable to test, unit probably not ready.  This usually
+	if (retval) {
+		/* Unable to test, unit probably not ready.  This usually
 		 * means there is no disc in the drive.  Mark as changed,
 		 * and we will figure it out later once the drive is
 		 * available again.  */
 
-                scsi_CDs[MINOR(cdi->dev)].device->changed = 1;
-                return 1; /* This will force a flush, if called from
-                           * check_disk_change */
+		scsi_CDs[MINOR(cdi->dev)].device->changed = 1;
+		return 1;	/* This will force a flush, if called from
+				 * check_disk_change */
 	};
 
 	retval = scsi_CDs[MINOR(cdi->dev)].device->changed;
-        scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
-        /* If the disk changed, the capacity will now be different,
-         * so we force a re-read of this information */
-        if (retval) {
+	scsi_CDs[MINOR(cdi->dev)].device->changed = 0;
+	/* If the disk changed, the capacity will now be different,
+	 * so we force a re-read of this information */
+	if (retval) {
 		/* check multisession offset etc */
-                sr_cd_check(cdi);
-		
-                 /* 
-                  * If the disk changed, the capacity will now be different,
-                  * so we force a re-read of this information 
-                  * Force 2048 for the sector size so that filesystems won't
-                  * be trying to use something that is too small if the disc
-                  * has changed.
-                  */
-                scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
+		sr_cd_check(cdi);
+
+		/* 
+		 * If the disk changed, the capacity will now be different,
+		 * so we force a re-read of this information 
+		 * Force 2048 for the sector size so that filesystems won't
+		 * be trying to use something that is too small if the disc
+		 * has changed.
+		 */
+		scsi_CDs[MINOR(cdi->dev)].needs_sector_size = 1;
 
-                scsi_CDs[MINOR(cdi->dev)].sector_size = 2048;
-        }
+		scsi_CDs[MINOR(cdi->dev)].sector_size = 2048;
+	}
 	return retval;
 }
 
@@ -170,7 +172,7 @@
  * end of a SCSI read / write, and will take on of several actions based on success or failure.
  */
 
-static void rw_intr (Scsi_Cmnd * SCpnt)
+static void rw_intr(Scsi_Cmnd * SCpnt)
 {
 	int result = SCpnt->result;
 	int this_count = SCpnt->this_count;
@@ -178,137 +180,130 @@
 	int block_sectors = 0;
 
 #ifdef DEBUG
-	printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data);
+	printk("sr.c done: %x %x\n", result, SCpnt->request.bh->b_data);
 #endif
-    /*
-      Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success.
-      Since this is a relatively rare error condition, no care is taken to
-      avoid unnecessary additional work such as memcpy's that could be avoided.
-    */
+	/*
+	   Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial success.
+	   Since this is a relatively rare error condition, no care is taken to
+	   avoid unnecessary additional work such as memcpy's that could be avoided.
+	 */
 
-	if (driver_byte(result) != 0 &&		    /* An error occurred */
-	    SCpnt->sense_buffer[0] == 0xF0 &&	    /* Sense data is valid */
+	if (driver_byte(result) != 0 &&		/* An error occurred */
+	    SCpnt->sense_buffer[0] == 0xF0 &&	/* Sense data is valid */
 	    (SCpnt->sense_buffer[2] == MEDIUM_ERROR ||
 	     SCpnt->sense_buffer[2] == VOLUME_OVERFLOW ||
-	     SCpnt->sense_buffer[2] == ILLEGAL_REQUEST))
-	  {
-	    long error_sector = (SCpnt->sense_buffer[3] << 24) |
-				(SCpnt->sense_buffer[4] << 16) |
-				(SCpnt->sense_buffer[5] << 8) |
-				SCpnt->sense_buffer[6];
-	    int device_nr = DEVICE_NR(SCpnt->request.rq_dev);
-	    if (SCpnt->request.bh != NULL)
-	      block_sectors = SCpnt->request.bh->b_size >> 9;
-	    if (block_sectors < 4) block_sectors = 4;
-	    if (scsi_CDs[device_nr].sector_size == 2048)
-	      error_sector <<= 2;
-	    error_sector &= ~ (block_sectors - 1);
-	    good_sectors = error_sector - SCpnt->request.sector;
-	    if (good_sectors < 0 || good_sectors >= this_count)
-	      good_sectors = 0;
-	    /*
-	      The SCSI specification allows for the value returned by READ
-	      CAPACITY to be up to 75 2K sectors past the last readable
-	      block.  Therefore, if we hit a medium error within the last
-	      75 2K sectors, we decrease the saved size value.
-	    */
-	    if ((error_sector >> 1) < sr_sizes[device_nr] &&
-		scsi_CDs[device_nr].capacity - error_sector < 4*75)
-	      sr_sizes[device_nr] = error_sector >> 1;
-	  }
-
-	if (good_sectors > 0)
-    { /* Some sectors were read successfully. */
-	if (SCpnt->use_sg == 0) {
-		    if (SCpnt->buffer != SCpnt->request.buffer)
-	    {
-		int offset;
-		offset = (SCpnt->request.sector % 4) << 9;
-		memcpy((char *)SCpnt->request.buffer,
-		       (char *)SCpnt->buffer + offset,
-		       good_sectors << 9);
-		/* Even though we are not using scatter-gather, we look
-		 * ahead and see if there is a linked request for the
-		 * other half of this buffer.  If there is, then satisfy
-		 * it. */
-		if((offset == 0) && good_sectors == 2 &&
-		   SCpnt->request.nr_sectors > good_sectors &&
-		   SCpnt->request.bh &&
-		   SCpnt->request.bh->b_reqnext &&
-		   SCpnt->request.bh->b_reqnext->b_size == 1024) {
-		    memcpy((char *)SCpnt->request.bh->b_reqnext->b_data,
-			   (char *)SCpnt->buffer + 1024,
-			   1024);
-		    good_sectors += 2;
-		};
+	     SCpnt->sense_buffer[2] == ILLEGAL_REQUEST)) {
+		long error_sector = (SCpnt->sense_buffer[3] << 24) |
+		(SCpnt->sense_buffer[4] << 16) |
+		(SCpnt->sense_buffer[5] << 8) |
+		SCpnt->sense_buffer[6];
+		int device_nr = DEVICE_NR(SCpnt->request.rq_dev);
+		if (SCpnt->request.bh != NULL)
+			block_sectors = SCpnt->request.bh->b_size >> 9;
+		if (block_sectors < 4)
+			block_sectors = 4;
+		if (scsi_CDs[device_nr].sector_size == 2048)
+			error_sector <<= 2;
+		error_sector &= ~(block_sectors - 1);
+		good_sectors = error_sector - SCpnt->request.sector;
+		if (good_sectors < 0 || good_sectors >= this_count)
+			good_sectors = 0;
+		/*
+		   The SCSI specification allows for the value returned by READ
+		   CAPACITY to be up to 75 2K sectors past the last readable
+		   block.  Therefore, if we hit a medium error within the last
+		   75 2K sectors, we decrease the saved size value.
+		 */
+		if ((error_sector >> 1) < sr_sizes[device_nr] &&
+		    scsi_CDs[device_nr].capacity - error_sector < 4 * 75)
+			sr_sizes[device_nr] = error_sector >> 1;
+	}
+	if (good_sectors > 0) {	/* Some sectors were read successfully. */
+		if (SCpnt->use_sg == 0) {
+			if (SCpnt->buffer != SCpnt->request.buffer) {
+				int offset;
+				offset = (SCpnt->request.sector % 4) << 9;
+				memcpy((char *) SCpnt->request.buffer,
+				       (char *) SCpnt->buffer + offset,
+				       good_sectors << 9);
+				/* Even though we are not using scatter-gather, we look
+				 * ahead and see if there is a linked request for the
+				 * other half of this buffer.  If there is, then satisfy
+				 * it. */
+				if ((offset == 0) && good_sectors == 2 &&
+				    SCpnt->request.nr_sectors > good_sectors &&
+				    SCpnt->request.bh &&
+				    SCpnt->request.bh->b_reqnext &&
+				    SCpnt->request.bh->b_reqnext->b_size == 1024) {
+					memcpy((char *) SCpnt->request.bh->b_reqnext->b_data,
+					   (char *) SCpnt->buffer + 1024,
+					       1024);
+					good_sectors += 2;
+				};
 
-		scsi_free(SCpnt->buffer, 2048);
-	    }
-	} else {
-		    struct scatterlist * sgpnt;
-		    int i;
-		    sgpnt = (struct scatterlist *) SCpnt->buffer;
-		    for(i=0; i<SCpnt->use_sg; i++) {
-		if (sgpnt[i].alt_address) {
-		    if (sgpnt[i].alt_address != sgpnt[i].address) {
-			memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
-		    };
-		    scsi_free(sgpnt[i].address, sgpnt[i].length);
+				scsi_free(SCpnt->buffer, 2048);
+			}
+		} else {
+			struct scatterlist *sgpnt;
+			int i;
+			sgpnt = (struct scatterlist *) SCpnt->buffer;
+			for (i = 0; i < SCpnt->use_sg; i++) {
+				if (sgpnt[i].alt_address) {
+					if (sgpnt[i].alt_address != sgpnt[i].address) {
+						memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+					};
+					scsi_free(sgpnt[i].address, sgpnt[i].length);
+				};
+			};
+			scsi_free(SCpnt->buffer, SCpnt->sglist_len);	/* Free list of scatter-gather pointers */
+			if (SCpnt->request.sector % 4)
+				good_sectors -= 2;
+			/* See   if there is a padding record at the end that needs to be removed */
+			if (good_sectors > SCpnt->request.nr_sectors)
+				good_sectors -= 2;
 		};
-		    };
-		    scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
-		    if(SCpnt->request.sector % 4) good_sectors -= 2;
-	    /* See   if there is a padding record at the end that needs to be removed */
-		    if(good_sectors > SCpnt->request.nr_sectors)
-		good_sectors -= 2;
-	};
 
 #ifdef DEBUG
-		printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors,
+		printk("(%x %x %x) ", SCpnt->request.bh, SCpnt->request.nr_sectors,
 		       good_sectors);
 #endif
-		if (SCpnt->request.nr_sectors > this_count)
-	{
+		if (SCpnt->request.nr_sectors > this_count) {
 			SCpnt->request.errors = 0;
 			if (!SCpnt->request.bh)
-			    panic("sr.c: linked page request (%lx %x)",
-		      SCpnt->request.sector, this_count);
-	}
-
-	SCpnt = end_scsi_request(SCpnt, 1, good_sectors);  /* All done */
-	if (result == 0)
-	  {
-	    requeue_sr_request(SCpnt);
-	    return;
-	  }
-    }
-
-    if (good_sectors == 0) {
-	/* We only come through here if no sectors were read successfully. */
-
-    /* Free up any indirection buffers we allocated for DMA purposes. */
-	if (SCpnt->use_sg) {
-	struct scatterlist * sgpnt;
-	int i;
-	sgpnt = (struct scatterlist *) SCpnt->buffer;
-	for(i=0; i<SCpnt->use_sg; i++) {
-	    if (sgpnt[i].alt_address) {
-		scsi_free(sgpnt[i].address, sgpnt[i].length);
-	    }
-	}
-	scsi_free(SCpnt->buffer, SCpnt->sglist_len);  /* Free list of scatter-gather pointers */
-	} else {
-	if (SCpnt->buffer != SCpnt->request.buffer)
-	    scsi_free(SCpnt->buffer, SCpnt->bufflen);
+				panic("sr.c: linked page request (%lx %x)",
+				      SCpnt->request.sector, this_count);
+		}
+		SCpnt = end_scsi_request(SCpnt, 1, good_sectors);	/* All done */
+		if (result == 0) {
+			requeue_sr_request(SCpnt);
+			return;
+		}
 	}
+	if (good_sectors == 0) {
+		/* We only come through here if no sectors were read successfully. */
 
-    }
+		/* Free up any indirection buffers we allocated for DMA purposes. */
+		if (SCpnt->use_sg) {
+			struct scatterlist *sgpnt;
+			int i;
+			sgpnt = (struct scatterlist *) SCpnt->buffer;
+			for (i = 0; i < SCpnt->use_sg; i++) {
+				if (sgpnt[i].alt_address) {
+					scsi_free(sgpnt[i].address, sgpnt[i].length);
+				}
+			}
+			scsi_free(SCpnt->buffer, SCpnt->sglist_len);	/* Free list of scatter-gather pointers */
+		} else {
+			if (SCpnt->buffer != SCpnt->request.buffer)
+				scsi_free(SCpnt->buffer, SCpnt->bufflen);
+		}
 
+	}
 	if (driver_byte(result) != 0) {
 		if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
 			if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
 				/* detected disc change.  set a bit and quietly refuse
-				 * further access.	*/
+				 * further access.    */
 
 				scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->changed = 1;
 				SCpnt = end_scsi_request(SCpnt, 0, this_count);
@@ -316,10 +311,9 @@
 				return;
 			}
 		}
-
 		if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
 			printk("sr%d: CD-ROM error: ",
-                               DEVICE_NR(SCpnt->request.rq_dev));
+			       DEVICE_NR(SCpnt->request.rq_dev));
 			print_sense("sr", SCpnt);
 			printk("command was: ");
 			print_command(SCpnt->cmnd);
@@ -330,95 +324,87 @@
 				return;
 			} else {
 				SCpnt = end_scsi_request(SCpnt, 0, this_count);
-				requeue_sr_request(SCpnt); /* Do next request */
+				requeue_sr_request(SCpnt);	/* Do next request */
 				return;
 			}
 
 		}
-
 		if (SCpnt->sense_buffer[2] == NOT_READY) {
 			printk(KERN_INFO "sr%d: CD-ROM not ready.  Make sure you have a disc in the drive.\n",
-                               DEVICE_NR(SCpnt->request.rq_dev));
+			       DEVICE_NR(SCpnt->request.rq_dev));
 			SCpnt = end_scsi_request(SCpnt, 0, this_count);
-			requeue_sr_request(SCpnt); /* Do next request */
+			requeue_sr_request(SCpnt);	/* Do next request */
 			return;
 		}
-
 		if (SCpnt->sense_buffer[2] == MEDIUM_ERROR) {
-		    printk("scsi%d: MEDIUM ERROR on "
-			   "channel %d, id %d, lun %d, CDB: ",
-			   SCpnt->host->host_no, (int) SCpnt->channel,
-			   (int) SCpnt->target, (int) SCpnt->lun);
-		    print_command(SCpnt->cmnd);
-		    print_sense("sr", SCpnt);
-		    SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
-		    requeue_sr_request(SCpnt);
-		    return;
+			printk("scsi%d: MEDIUM ERROR on "
+			       "channel %d, id %d, lun %d, CDB: ",
+			       SCpnt->host->host_no, (int) SCpnt->channel,
+			       (int) SCpnt->target, (int) SCpnt->lun);
+			print_command(SCpnt->cmnd);
+			print_sense("sr", SCpnt);
+			SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
+			requeue_sr_request(SCpnt);
+			return;
 		}
-
 		if (SCpnt->sense_buffer[2] == VOLUME_OVERFLOW) {
-		    printk("scsi%d: VOLUME OVERFLOW on "
-			   "channel %d, id %d, lun %d, CDB: ",
-			   SCpnt->host->host_no, (int) SCpnt->channel,
-			   (int) SCpnt->target, (int) SCpnt->lun);
-		    print_command(SCpnt->cmnd);
-		    print_sense("sr", SCpnt);
-		    SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
-		    requeue_sr_request(SCpnt);
-		    return;
+			printk("scsi%d: VOLUME OVERFLOW on "
+			       "channel %d, id %d, lun %d, CDB: ",
+			       SCpnt->host->host_no, (int) SCpnt->channel,
+			       (int) SCpnt->target, (int) SCpnt->lun);
+			print_command(SCpnt->cmnd);
+			print_sense("sr", SCpnt);
+			SCpnt = end_scsi_request(SCpnt, 0, block_sectors);
+			requeue_sr_request(SCpnt);
+			return;
 		}
-        }
-
+	}
 	/* We only get this far if we have an error we have not recognized */
-	if(result) {
-	printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
-	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
-	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
-	       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun,
-	       result);
-
-	if (status_byte(result) == CHECK_CONDITION)
-	    print_sense("sr", SCpnt);
-
-	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
-	requeue_sr_request(SCpnt);
-    }
+	if (result) {
+		printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
+		       scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->host->host_no,
+		   scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->id,
+		  scsi_CDs[DEVICE_NR(SCpnt->request.rq_dev)].device->lun,
+		       result);
+
+		if (status_byte(result) == CHECK_CONDITION)
+			print_sense("sr", SCpnt);
+
+		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
+		requeue_sr_request(SCpnt);
+	}
 }
 
 static int sr_open(struct cdrom_device_info *cdi, int purpose)
 {
-    check_disk_change(cdi->dev);
+	check_disk_change(cdi->dev);
 
-    if(   MINOR(cdi->dev) >= sr_template.dev_max 
-       || !scsi_CDs[MINOR(cdi->dev)].device)
-      {
-	return -ENXIO;   /* No such device */
-      }
-
-    /*
-     * If the device is in error recovery, wait until it is done.
-     * If the device is offline, then disallow any access to it.
-     */
-    if( !scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device) )
-      {
-        return -ENXIO;
-      }
-
-    scsi_CDs[MINOR(cdi->dev)].device->access_count++;
-    if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
-	__MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
-    if(sr_template.module)
-        __MOD_INC_USE_COUNT(sr_template.module);
-
-    /* If this device did not have media in the drive at boot time, then
-     * we would have been unable to get the sector size.  Check to see if
-     * this is the case, and try again.
-     */
+	if (MINOR(cdi->dev) >= sr_template.dev_max
+	    || !scsi_CDs[MINOR(cdi->dev)].device) {
+		return -ENXIO;	/* No such device */
+	}
+	/*
+	 * If the device is in error recovery, wait until it is done.
+	 * If the device is offline, then disallow any access to it.
+	 */
+	if (!scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device)) {
+		return -ENXIO;
+	}
+	scsi_CDs[MINOR(cdi->dev)].device->access_count++;
+	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
+		__MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
+	if (sr_template.module)
+		__MOD_INC_USE_COUNT(sr_template.module);
+
+	/* If this device did not have media in the drive at boot time, then
+	 * we would have been unable to get the sector size.  Check to see if
+	 * this is the case, and try again.
+	 */
 
-    if(scsi_CDs[MINOR(cdi->dev)].needs_sector_size)
-	get_sectorsize(MINOR(cdi->dev));
+	if (scsi_CDs[MINOR(cdi->dev)].needs_sector_size)
+		get_sectorsize(MINOR(cdi->dev));
 
-    return 0;
+	return 0;
 }
 
 /*
@@ -427,111 +413,106 @@
  * translate them to SCSI commands.
  */
 
-static void do_sr_request (void)
+static void do_sr_request(void)
 {
-    Scsi_Cmnd * SCpnt = NULL;
-    struct request * req = NULL;
-    Scsi_Device * SDev;
-    int flag = 0;
-
-    while (1==1){
-	if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
-	    return;
-	};
+	Scsi_Cmnd *SCpnt = NULL;
+	struct request *req = NULL;
+	Scsi_Device *SDev;
+	int flag = 0;
 
-	INIT_SCSI_REQUEST;
+	while (1 == 1) {
+		if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
+			return;
+		};
 
-	SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
+		INIT_SCSI_REQUEST;
 
-        /*
-         * If the host for this device is in error recovery mode, don't
-         * do anything at all here.  When the host leaves error recovery
-         * mode, it will automatically restart things and start queueing
-         * commands again.
-         */
-        if( SDev->host->in_recovery )
-          {
-            return;
-          }
+		SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
 
-	/*
-	 * I am not sure where the best place to do this is.  We need
-	 * to hook in a place where we are likely to come if in user
-	 * space.
-	 */
-	if( SDev->was_reset )
-	{
- 	    /*
- 	     * We need to relock the door, but we might
- 	     * be in an interrupt handler.  Only do this
- 	     * from user space, since we do not want to
- 	     * sleep from an interrupt.
- 	     */
- 	    if( SDev->removable && !in_interrupt() )
- 	    {
-		spin_unlock_irq(&io_request_lock);		/* FIXME!!!! */
-		scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
-		spin_lock_irq(&io_request_lock);		/* FIXME!!!! */
-		/* scsi_ioctl may allow CURRENT to change, so start over. */
-		SDev->was_reset = 0;
-		continue;
- 	    }
- 	    SDev->was_reset = 0;
-	}
-
-	/* we do lazy blocksize switching (when reading XA sectors,
-	 * see CDROMREADMODE2 ioctl) */
-	if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) {
-	    if (!in_interrupt())
-		sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev),2048);
+		/*
+		 * If the host for this device is in error recovery mode, don't
+		 * do anything at all here.  When the host leaves error recovery
+		 * mode, it will automatically restart things and start queueing
+		 * commands again.
+		 */
+		if (SDev->host->in_recovery) {
+			return;
+		}
+		/*
+		 * I am not sure where the best place to do this is.  We need
+		 * to hook in a place where we are likely to come if in user
+		 * space.
+		 */
+		if (SDev->was_reset) {
+			/*
+			 * We need to relock the door, but we might
+			 * be in an interrupt handler.  Only do this
+			 * from user space, since we do not want to
+			 * sleep from an interrupt.
+			 */
+			if (SDev->removable && !in_interrupt()) {
+				spin_unlock_irq(&io_request_lock);	/* FIXME!!!! */
+				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
+				spin_lock_irq(&io_request_lock);	/* FIXME!!!! */
+				/* scsi_ioctl may allow CURRENT to change, so start over. */
+				SDev->was_reset = 0;
+				continue;
+			}
+			SDev->was_reset = 0;
+		}
+		/* we do lazy blocksize switching (when reading XA sectors,
+		 * see CDROMREADMODE2 ioctl) */
+		if (scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].sector_size > 2048) {
+			if (!in_interrupt())
+				sr_set_blocklength(DEVICE_NR(CURRENT->rq_dev), 2048);
 #if 1
-            else
-                printk("sr: can't switch blocksize: in interrupt\n");
+			else
+				printk("sr: can't switch blocksize: in interrupt\n");
 #endif
-	}
-
-	if (flag++ == 0)
-	    SCpnt = scsi_allocate_device(&CURRENT,
-				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
-	else SCpnt = NULL;
-
-	/* This is a performance enhancement.  We dig down into the request list and
-	 * try to find a queueable request (i.e. device not busy, and host able to
-	 * accept another command.  If we find one, then we queue it. This can
-	 * make a big difference on systems with more than one disk drive.  We want
-	 * to have the interrupts off when monkeying with the request list, because
-	 * otherwise the kernel might try to slip in a request in between somewhere. */
-
-	if (!SCpnt && sr_template.nr_dev > 1){
-	    struct request *req1;
-	    req1 = NULL;
-	    req = CURRENT;
-	    while(req){
-		SCpnt = scsi_request_queueable(req,
-					  scsi_CDs[DEVICE_NR(req->rq_dev)].device);
-		if(SCpnt) break;
-		req1 = req;
-		req = req->next;
-	    }
-	    if (SCpnt && req->rq_status == RQ_INACTIVE) {
-		if (req == CURRENT)
-		    CURRENT = CURRENT->next;
+		}
+		if (flag++ == 0)
+			SCpnt = scsi_allocate_device(&CURRENT,
+			 scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
 		else
-		    req1->next = req->next;
-	    }
-	}
+			SCpnt = NULL;
 
-	if (!SCpnt)
-	    return; /* Could not find anything to do */
+		/* This is a performance enhancement.  We dig down into the request list and
+		 * try to find a queueable request (i.e. device not busy, and host able to
+		 * accept another command.  If we find one, then we queue it. This can
+		 * make a big difference on systems with more than one disk drive.  We want
+		 * to have the interrupts off when monkeying with the request list, because
+		 * otherwise the kernel might try to slip in a request in between somewhere. */
+
+		if (!SCpnt && sr_template.nr_dev > 1) {
+			struct request *req1;
+			req1 = NULL;
+			req = CURRENT;
+			while (req) {
+				SCpnt = scsi_request_queueable(req,
+				scsi_CDs[DEVICE_NR(req->rq_dev)].device);
+				if (SCpnt)
+					break;
+				req1 = req;
+				req = req->next;
+			}
+			if (SCpnt && req->rq_status == RQ_INACTIVE) {
+				if (req == CURRENT)
+					CURRENT = CURRENT->next;
+				else
+					req1->next = req->next;
+			}
+		}
+		if (!SCpnt)
+			return;	/* Could not find anything to do */
 
-	wake_up(&wait_for_request);
+		wake_up(&wait_for_request);
 
-	/* Queue command */
-	requeue_sr_request(SCpnt);
-    }  /* While */
+		/* Queue command */
+		requeue_sr_request(SCpnt);
+	}			/* While */
 }
 
-void requeue_sr_request (Scsi_Cmnd * SCpnt)
+void requeue_sr_request(Scsi_Cmnd * SCpnt)
 {
 	unsigned int dev, block, realcount;
 	unsigned char cmd[10], *buffer, tries;
@@ -539,244 +520,234 @@
 
 	tries = 2;
 
- repeat:
-	if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
+repeat:
+	if (!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {
 		do_sr_request();
 		return;
 	}
-
-	dev =  MINOR(SCpnt->request.rq_dev);
+	dev = MINOR(SCpnt->request.rq_dev);
 	block = SCpnt->request.sector;
 	buffer = NULL;
 	this_count = 0;
 
 	if (dev >= sr_template.nr_dev) {
-		/* printk("CD-ROM request error: invalid device.\n");			*/
+		/* printk("CD-ROM request error: invalid device.\n");                   */
 		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 		tries = 2;
 		goto repeat;
 	}
-
 	if (!scsi_CDs[dev].use) {
-		/* printk("CD-ROM request error: device marked not in use.\n");		*/
+		/* printk("CD-ROM request error: device marked not in use.\n");         */
+		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+		tries = 2;
+		goto repeat;
+	}
+	if (!scsi_CDs[dev].device->online) {
 		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 		tries = 2;
 		goto repeat;
 	}
-
-	if( !scsi_CDs[dev].device->online )
-          {
-            SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-            tries = 2;
-            goto repeat;
-          }
-
 	if (scsi_CDs[dev].device->changed) {
-	/*
-	 * quietly refuse to do anything to a changed disc
-	 * until the changed bit has been reset
-	 */
-		/* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");	*/
+		/*
+		 * quietly refuse to do anything to a changed disc
+		 * until the changed bit has been reset
+		 */
+		/* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");      */
 		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
 		tries = 2;
 		goto repeat;
 	}
-
-	switch (SCpnt->request.cmd)
-    {
-    case WRITE:
-	SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
-	goto repeat;
-	break;
-    case READ :
-	cmd[0] = READ_6;
-	break;
-    default :
-	panic ("Unknown sr command %d\n", SCpnt->request.cmd);
-    }
+	switch (SCpnt->request.cmd) {
+	case WRITE:
+		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+		goto repeat;
+		break;
+	case READ:
+		cmd[0] = READ_6;
+		break;
+	default:
+		panic("Unknown sr command %d\n", SCpnt->request.cmd);
+	}
 
 	cmd[1] = (SCpnt->lun << 5) & 0xe0;
 
-    /*
-     * Now do the grungy work of figuring out which sectors we need, and
-     * where in memory we are going to put them.
-     *
-     * The variables we need are:
-     *
-     * this_count= number of 512 byte sectors being read
-     * block     = starting cdrom sector to read.
-     * realcount = # of cdrom sectors to read
-     *
-     * The major difference between a scsi disk and a scsi cdrom
-     * is that we will always use scatter-gather if we can, because we can
-     * work around the fact that the buffer cache has a block size of 1024,
-     * and we have 2048 byte sectors.  This code should work for buffers that
-     * are any multiple of 512 bytes long.
-     */
+	/*
+	 * Now do the grungy work of figuring out which sectors we need, and
+	 * where in memory we are going to put them.
+	 *
+	 * The variables we need are:
+	 *
+	 * this_count= number of 512 byte sectors being read
+	 * block     = starting cdrom sector to read.
+	 * realcount = # of cdrom sectors to read
+	 *
+	 * The major difference between a scsi disk and a scsi cdrom
+	 * is that we will always use scatter-gather if we can, because we can
+	 * work around the fact that the buffer cache has a block size of 1024,
+	 * and we have 2048 byte sectors.  This code should work for buffers that
+	 * are any multiple of 512 bytes long.
+	 */
 
 	SCpnt->use_sg = 0;
 
 	if (SCpnt->host->sg_tablesize > 0 &&
 	    (!scsi_need_isa_buffer ||
-	 scsi_dma_free_sectors >= 10)) {
-	struct buffer_head * bh;
-	struct scatterlist * sgpnt;
-	int count, this_count_max;
-	bh = SCpnt->request.bh;
-	this_count = 0;
-	count = 0;
-	this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
-	/* Calculate how many links we can use.  First see if we need
-	 * a padding record at the start */
-	this_count = SCpnt->request.sector % 4;
-	if(this_count) count++;
-	while(bh && count < SCpnt->host->sg_tablesize) {
-	    if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
-	    this_count += (bh->b_size >> 9);
-	    count++;
-	    bh = bh->b_reqnext;
-	};
-	/* Fix up in case of an odd record at the end */
-	end_rec = 0;
-	if(this_count % 4) {
-	    if (count < SCpnt->host->sg_tablesize) {
-		count++;
-		end_rec = (4 - (this_count % 4)) << 9;
-		this_count += 4 - (this_count % 4);
-	    } else {
-		count--;
-		this_count -= (this_count % 4);
-	    };
-	};
-	SCpnt->use_sg = count;  /* Number of chains */
-	/* scsi_malloc can only allocate in chunks of 512 bytes */
-	count  = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;
-
-	SCpnt->sglist_len = count;
-	sgpnt = (struct scatterlist * ) scsi_malloc(count);
-	if (!sgpnt) {
-	    printk("Warning - running *really* short on DMA buffers\n");
-	    SCpnt->use_sg = 0;  /* No memory left - bail out */
-	} else {
-	    buffer = (unsigned char *) sgpnt;
-	    count = 0;
-	    bh = SCpnt->request.bh;
-	    if(SCpnt->request.sector % 4) {
-		sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
-		sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
-		if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
-		sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete
-								    if needed */
-		count++;
-	    };
-	    for(bh = SCpnt->request.bh; count < SCpnt->use_sg;
-		count++, bh = bh->b_reqnext) {
-		if (bh) { /* Need a placeholder at the end of the record? */
-		    sgpnt[count].address = bh->b_data;
-		    sgpnt[count].length = bh->b_size;
-		    sgpnt[count].alt_address = NULL;
-		} else {
-		    sgpnt[count].address = (char *) scsi_malloc(end_rec);
-		    if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
-		    sgpnt[count].length = end_rec;
-		    sgpnt[count].alt_address = sgpnt[count].address;
-		    if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
-		    break;
+	     scsi_dma_free_sectors >= 10)) {
+		struct buffer_head *bh;
+		struct scatterlist *sgpnt;
+		int count, this_count_max;
+		bh = SCpnt->request.bh;
+		this_count = 0;
+		count = 0;
+		this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
+		/* Calculate how many links we can use.  First see if we need
+		 * a padding record at the start */
+		this_count = SCpnt->request.sector % 4;
+		if (this_count)
+			count++;
+		while (bh && count < SCpnt->host->sg_tablesize) {
+			if ((this_count + (bh->b_size >> 9)) > this_count_max)
+				break;
+			this_count += (bh->b_size >> 9);
+			count++;
+			bh = bh->b_reqnext;
 		};
-		if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
-		    ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) {
-		    sgpnt[count].alt_address = sgpnt[count].address;
-		    /* We try to avoid exhausting the DMA pool, since it is easier
-		     * to control usage here.  In other places we might have a more
-		     * pressing need, and we would be screwed if we ran out */
-		    if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
-			sgpnt[count].address = NULL;
-		    } else {
-			sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
-		    };
-		    /* If we start running low on DMA buffers, we abort the scatter-gather
-		     * operation, and free all of the memory we have allocated.  We want to
-		     * ensure that all scsi operations are able to do at least a non-scatter/gather
-		     * operation */
-		    if(sgpnt[count].address == NULL){ /* Out of dma memory */
-			printk("Warning: Running low on SCSI DMA buffers\n");
-			/* Try switching back to a non scatter-gather operation. */
-			while(--count >= 0){
-			    if(sgpnt[count].alt_address)
-				scsi_free(sgpnt[count].address, sgpnt[count].length);
+		/* Fix up in case of an odd record at the end */
+		end_rec = 0;
+		if (this_count % 4) {
+			if (count < SCpnt->host->sg_tablesize) {
+				count++;
+				end_rec = (4 - (this_count % 4)) << 9;
+				this_count += 4 - (this_count % 4);
+			} else {
+				count--;
+				this_count -= (this_count % 4);
 			};
-			SCpnt->use_sg = 0;
-			scsi_free(buffer, SCpnt->sglist_len);
-			break;
-		    }; /* if address == NULL */
-		};  /* if need DMA fixup */
-	    };  /* for loop to fill list */
+		};
+		SCpnt->use_sg = count;	/* Number of chains */
+		/* scsi_malloc can only allocate in chunks of 512 bytes */
+		count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;
+
+		SCpnt->sglist_len = count;
+		sgpnt = (struct scatterlist *) scsi_malloc(count);
+		if (!sgpnt) {
+			printk("Warning - running *really* short on DMA buffers\n");
+			SCpnt->use_sg = 0;	/* No memory left - bail out */
+		} else {
+			buffer = (unsigned char *) sgpnt;
+			count = 0;
+			bh = SCpnt->request.bh;
+			if (SCpnt->request.sector % 4) {
+				sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
+				sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+				if (!sgpnt[count].address)
+					panic("SCSI DMA pool exhausted.");
+				sgpnt[count].alt_address = sgpnt[count].address;	/* Flag to delete
+											   if needed */
+				count++;
+			};
+			for (bh = SCpnt->request.bh; count < SCpnt->use_sg;
+			     count++, bh = bh->b_reqnext) {
+				if (bh) {	/* Need a placeholder at the end of the record? */
+					sgpnt[count].address = bh->b_data;
+					sgpnt[count].length = bh->b_size;
+					sgpnt[count].alt_address = NULL;
+				} else {
+					sgpnt[count].address = (char *) scsi_malloc(end_rec);
+					if (!sgpnt[count].address)
+						panic("SCSI DMA pool exhausted.");
+					sgpnt[count].length = end_rec;
+					sgpnt[count].alt_address = sgpnt[count].address;
+					if (count + 1 != SCpnt->use_sg)
+						panic("Bad sr request list");
+					break;
+				};
+				if (virt_to_phys(sgpnt[count].address) + sgpnt[count].length - 1 >
+				    ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) {
+					sgpnt[count].alt_address = sgpnt[count].address;
+					/* We try to avoid exhausting the DMA pool, since it is easier
+					 * to control usage here.  In other places we might have a more
+					 * pressing need, and we would be screwed if we ran out */
+					if (scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
+						sgpnt[count].address = NULL;
+					} else {
+						sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+					};
+					/* If we start running low on DMA buffers, we abort the scatter-gather
+					 * operation, and free all of the memory we have allocated.  We want to
+					 * ensure that all scsi operations are able to do at least a non-scatter/gather
+					 * operation */
+					if (sgpnt[count].address == NULL) {	/* Out of dma memory */
+						printk("Warning: Running low on SCSI DMA buffers\n");
+						/* Try switching back to a non scatter-gather operation. */
+						while (--count >= 0) {
+							if (sgpnt[count].alt_address)
+								scsi_free(sgpnt[count].address, sgpnt[count].length);
+						};
+						SCpnt->use_sg = 0;
+						scsi_free(buffer, SCpnt->sglist_len);
+						break;
+					};	/* if address == NULL */
+				};	/* if need DMA fixup */
+			};	/* for loop to fill list */
 #ifdef DEBUG
-	    printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector,
-		   this_count,
-		   SCpnt->request.current_nr_sectors,
-		   SCpnt->request.nr_sectors);
-	    for(count=0; count<SCpnt->use_sg; count++)
-		printk("SGlist: %d %x %x %x\n", count,
-		       sgpnt[count].address,
-		       sgpnt[count].alt_address,
-		       sgpnt[count].length);
+			printk("SR: %d %d %d %d %d *** ", SCpnt->use_sg, SCpnt->request.sector,
+			       this_count,
+			       SCpnt->request.current_nr_sectors,
+			       SCpnt->request.nr_sectors);
+			for (count = 0; count < SCpnt->use_sg; count++)
+				printk("SGlist: %d %x %x %x\n", count,
+				       sgpnt[count].address,
+				       sgpnt[count].alt_address,
+				       sgpnt[count].length);
 #endif
-	};  /* Able to allocate scatter-gather list */
+		};		/* Able to allocate scatter-gather list */
 	};
 
-	if (SCpnt->use_sg == 0){
-	/* We cannot use scatter-gather.  Do this the old fashion way */
-	if (!SCpnt->request.bh)
-	    this_count = SCpnt->request.nr_sectors;
-	else
-	    this_count = (SCpnt->request.bh->b_size >> 9);
+	if (SCpnt->use_sg == 0) {
+		/* We cannot use scatter-gather.  Do this the old fashion way */
+		if (!SCpnt->request.bh)
+			this_count = SCpnt->request.nr_sectors;
+		else
+			this_count = (SCpnt->request.bh->b_size >> 9);
 
-	start = block % 4;
-	if (start)
-	    {
-	    this_count = ((this_count > 4 - start) ?
-			  (4 - start) : (this_count));
-	    buffer = (unsigned char *) scsi_malloc(2048);
-	    }
-	else if (this_count < 4)
-	    {
-	    buffer = (unsigned char *) scsi_malloc(2048);
-	    }
-	else
-	    {
-	    this_count -= this_count % 4;
-	    buffer = (unsigned char *) SCpnt->request.buffer;
-	    if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &&
-		SCpnt->host->unchecked_isa_dma)
-		buffer = (unsigned char *) scsi_malloc(this_count << 9);
-	    }
+		start = block % 4;
+		if (start) {
+			this_count = ((this_count > 4 - start) ?
+				      (4 - start) : (this_count));
+			buffer = (unsigned char *) scsi_malloc(2048);
+		} else if (this_count < 4) {
+			buffer = (unsigned char *) scsi_malloc(2048);
+		} else {
+			this_count -= this_count % 4;
+			buffer = (unsigned char *) SCpnt->request.buffer;
+			if (virt_to_phys(buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &&
+			    SCpnt->host->unchecked_isa_dma)
+				buffer = (unsigned char *) scsi_malloc(this_count << 9);
+		}
 	};
 
 	if (scsi_CDs[dev].sector_size == 2048)
-	block = block >> 2; /* These are the sectors that the cdrom uses */
+		block = block >> 2;	/* These are the sectors that the cdrom uses */
 	else
-	block = block & 0xfffffffc;
+		block = block & 0xfffffffc;
 
 	realcount = (this_count + 3) / 4;
 
-	if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
+	if (scsi_CDs[dev].sector_size == 512)
+		realcount = realcount << 2;
 
-        /*
-         * Note: The scsi standard says that READ_6 is *optional*, while
-         * READ_10 is mandatory.   Thus there is no point in using
-         * READ_6.
-         */
-	if (scsi_CDs[dev].ten)
-          
-    {
-		if (realcount > 0xffff)
-	{
+	/*
+	 * Note: The scsi standard says that READ_6 is *optional*, while
+	 * READ_10 is mandatory.   Thus there is no point in using
+	 * READ_6.
+	 */
+	if (scsi_CDs[dev].ten) {
+		if (realcount > 0xffff) {
 			realcount = 0xffff;
 			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
-	}
-
-		cmd[0] += READ_10 - READ_6 ;
+		}
+		cmd[0] += READ_10 - READ_6;
 		cmd[2] = (unsigned char) (block >> 24) & 0xff;
 		cmd[3] = (unsigned char) (block >> 16) & 0xff;
 		cmd[4] = (unsigned char) (block >> 8) & 0xff;
@@ -784,167 +755,172 @@
 		cmd[6] = cmd[9] = 0;
 		cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
 		cmd[8] = (unsigned char) realcount & 0xff;
-    }
-	else
-    {
-	if (realcount > 0xff)
-	{
-	    realcount = 0xff;
-	    this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
+	} else {
+		if (realcount > 0xff) {
+			realcount = 0xff;
+			this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
+		}
+		cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+		cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+		cmd[3] = (unsigned char) block & 0xff;
+		cmd[4] = (unsigned char) realcount;
+		cmd[5] = 0;
 	}
 
-	cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
-	cmd[2] = (unsigned char) ((block >> 8) & 0xff);
-	cmd[3] = (unsigned char) block & 0xff;
-	cmd[4] = (unsigned char) realcount;
-	cmd[5] = 0;
-    }
-
 #ifdef DEBUG
-    {
-	int i;
-	printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
-	printk("Use sg: %d\n", SCpnt->use_sg);
-	printk("Dumping command: ");
-	for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
-	printk("\n");
-    };
+	{
+		int i;
+		printk("ReadCD: %d %d %d %d\n", block, realcount, buffer, this_count);
+		printk("Use sg: %d\n", SCpnt->use_sg);
+		printk("Dumping command: ");
+		for (i = 0; i < 12; i++)
+			printk("%2.2x ", cmd[i]);
+		printk("\n");
+	};
 #endif
 
-    /* Some dumb host adapters can speed transfers by knowing the
-     * minimum transfersize in advance.
-     *
-     * We shouldn't disconnect in the middle of a sector, but the cdrom
-     * sector size can be larger than the size of a buffer and the
-     * transfer may be split to the size of a buffer.  So it's safe to
-     * assume that we can at least transfer the minimum of the buffer
-     * size (1024) and the sector size between each connect / disconnect.
-     */
+	/* Some dumb host adapters can speed transfers by knowing the
+	 * minimum transfersize in advance.
+	 *
+	 * We shouldn't disconnect in the middle of a sector, but the cdrom
+	 * sector size can be larger than the size of a buffer and the
+	 * transfer may be split to the size of a buffer.  So it's safe to
+	 * assume that we can at least transfer the minimum of the buffer
+	 * size (1024) and the sector size between each connect / disconnect.
+	 */
 
-    SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
-	1024 : scsi_CDs[dev].sector_size;
+	SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
+	    1024 : scsi_CDs[dev].sector_size;
 
 	SCpnt->this_count = this_count;
-	scsi_do_cmd (SCpnt, (void *) cmd, buffer,
-		 realcount * scsi_CDs[dev].sector_size,
-		 rw_intr, SR_TIMEOUT, MAX_RETRIES);
+	scsi_do_cmd(SCpnt, (void *) cmd, buffer,
+		    realcount * scsi_CDs[dev].sector_size,
+		    rw_intr, SR_TIMEOUT, MAX_RETRIES);
 }
 
-static int sr_detect(Scsi_Device * SDp){
+static int sr_detect(Scsi_Device * SDp)
+{
 
-    if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
+	if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
+		return 0;
 
-    printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
-	   sr_template.dev_noticed++,
-	   SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+	printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
+	       sr_template.dev_noticed++,
+	       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 
-    return 1;
+	return 1;
 }
 
-static int sr_attach(Scsi_Device * SDp){
-    Scsi_CD * cpnt;
-    int i;
-
-    if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
-
-    if (sr_template.nr_dev >= sr_template.dev_max)
-    {
-	SDp->attached--;
-	return 1;
-    }
+static int sr_attach(Scsi_Device * SDp)
+{
+	Scsi_CD *cpnt;
+	int i;
 
-    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
-	if(!cpnt->device) break;
+	if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
+		return 1;
 
-    if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
+	if (sr_template.nr_dev >= sr_template.dev_max) {
+		SDp->attached--;
+		return 1;
+	}
+	for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++)
+		if (!cpnt->device)
+			break;
+
+	if (i >= sr_template.dev_max)
+		panic("scsi_devices corrupt (sr)");
 
-    SDp->scsi_request_fn = do_sr_request;
-    scsi_CDs[i].device = SDp;
+	SDp->scsi_request_fn = do_sr_request;
+	scsi_CDs[i].device = SDp;
 
-    sr_template.nr_dev++;
-    if(sr_template.nr_dev > sr_template.dev_max)
-	panic ("scsi_devices corrupt (sr)");
-    return 0;
+	sr_template.nr_dev++;
+	if (sr_template.nr_dev > sr_template.dev_max)
+		panic("scsi_devices corrupt (sr)");
+	return 0;
 }
 
 
-static void sr_init_done (Scsi_Cmnd * SCpnt)
+static void sr_init_done(Scsi_Cmnd * SCpnt)
 {
-    struct request * req;
+	struct request *req;
 
-    req = &SCpnt->request;
-    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
+	req = &SCpnt->request;
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
 
-    if (req->sem != NULL) {
-	up(req->sem);
-    }
+	if (req->sem != NULL) {
+		up(req->sem);
+	}
 }
 
-void get_sectorsize(int i){
-    unsigned char cmd[10];
-    unsigned char *buffer;
-    int the_result, retries;
-    Scsi_Cmnd * SCpnt;
-    unsigned long flags;
-
-    buffer = (unsigned char *) scsi_malloc(512);
-    SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
-
-    retries = 3;
-    do {
-	cmd[0] = READ_CAPACITY;
-	cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
-	memset ((void *) &cmd[2], 0, 8);
-	SCpnt->request.rq_status = RQ_SCSI_BUSY;  /* Mark as really busy */
-	SCpnt->cmd_len = 0;
+void get_sectorsize(int i)
+{
+	unsigned char cmd[10];
+	unsigned char *buffer;
+	int the_result, retries;
+	Scsi_Cmnd *SCpnt;
+	unsigned long flags;
 
-	memset(buffer, 0, 8);
+	buffer = (unsigned char *) scsi_malloc(512);
+	SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
 
-	/* Do the command and wait.. */
-	{
-	    DECLARE_MUTEX_LOCKED(sem);
-	    SCpnt->request.sem = &sem;
-	    spin_lock_irqsave(&io_request_lock, flags);
-	    scsi_do_cmd (SCpnt,
-			 (void *) cmd, (void *) buffer,
-			 512, sr_init_done,  SR_TIMEOUT,
-			 MAX_RETRIES);
-	    spin_unlock_irqrestore(&io_request_lock, flags);
-	    down(&sem);
-	}
-
-	the_result = SCpnt->result;
-	retries--;
-
-    } while(the_result && retries);
-
-
-    wake_up(&SCpnt->device->device_wait);
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if (the_result) {
-	scsi_CDs[i].capacity = 0x1fffff;
-	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
-	scsi_CDs[i].needs_sector_size = 1;
-    } else {
-	if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
-	   (long*)&scsi_CDs[i].capacity)) {
-		scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
-					    (buffer[1] << 16) |
-					    (buffer[2] << 8) |
-					     buffer[3]);
-	}
-	scsi_CDs[i].sector_size = (buffer[4] << 24) |
-	    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
-	switch (scsi_CDs[i].sector_size) {
-		/*
-		 * HP 4020i CD-Recorder reports 2340 byte sectors
-		 * Philips CD-Writers report 2352 byte sectors
-		 *
-		 * Use 2k sectors for them..
-		 */
-		case 0: case 2340: case 2352:
+	retries = 3;
+	do {
+		cmd[0] = READ_CAPACITY;
+		cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+		memset((void *) &cmd[2], 0, 8);
+		SCpnt->request.rq_status = RQ_SCSI_BUSY;	/* Mark as really busy */
+		SCpnt->cmd_len = 0;
+
+		memset(buffer, 0, 8);
+
+		/* Do the command and wait.. */
+		{
+			DECLARE_MUTEX_LOCKED(sem);
+			SCpnt->request.sem = &sem;
+			spin_lock_irqsave(&io_request_lock, flags);
+			scsi_do_cmd(SCpnt,
+				    (void *) cmd, (void *) buffer,
+				    512, sr_init_done, SR_TIMEOUT,
+				    MAX_RETRIES);
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			down(&sem);
+		}
+
+		the_result = SCpnt->result;
+		retries--;
+
+	} while (the_result && retries);
+
+
+	wake_up(&SCpnt->device->device_wait);
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	if (the_result) {
+		scsi_CDs[i].capacity = 0x1fffff;
+		scsi_CDs[i].sector_size = 2048;		/* A guess, just in case */
+		scsi_CDs[i].needs_sector_size = 1;
+	} else {
+#if 0
+		if (cdrom_get_last_written(MKDEV(MAJOR_NR, i),
+					 (long *) &scsi_CDs[i].capacity))
+#endif
+			scsi_CDs[i].capacity = 1 + ((buffer[0] << 24) |
+						    (buffer[1] << 16) |
+						    (buffer[2] << 8) |
+						    buffer[3]);
+		scsi_CDs[i].sector_size = (buffer[4] << 24) |
+		    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+		switch (scsi_CDs[i].sector_size) {
+			/*
+			 * HP 4020i CD-Recorder reports 2340 byte sectors
+			 * Philips CD-Writers report 2352 byte sectors
+			 *
+			 * Use 2k sectors for them..
+			 */
+		case 0:
+		case 2340:
+		case 2352:
 			scsi_CDs[i].sector_size = 2048;
 			/* fall through */
 		case 2048:
@@ -953,94 +929,95 @@
 		case 512:
 			break;
 		default:
-			printk ("sr%d: unsupported sector size %d.\n",
-				i, scsi_CDs[i].sector_size);
+			printk("sr%d: unsupported sector size %d.\n",
+			       i, scsi_CDs[i].sector_size);
 			scsi_CDs[i].capacity = 0;
 			scsi_CDs[i].needs_sector_size = 1;
-	}
+		}
 
-        /*
-         * Add this so that we have the ability to correctly gauge
-         * what the device is capable of.
-         */
-	scsi_CDs[i].needs_sector_size = 0;
-	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
-    };
-    scsi_free(buffer, 512);
+		/*
+		 * Add this so that we have the ability to correctly gauge
+		 * what the device is capable of.
+		 */
+		scsi_CDs[i].needs_sector_size = 0;
+		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
+	};
+	scsi_free(buffer, 512);
 }
 
-void get_capabilities(int i){
-    unsigned char cmd[6];
-    unsigned char *buffer;
-    int           rc,n;
-
-    static char *loadmech[] = {
-        "caddy",
-        "tray",
-        "pop-up",
-        "",
-        "changer",
-        "changer",
-        "",
-        ""
-    };          
-
-    buffer = (unsigned char *) scsi_malloc(512);
-    cmd[0] = MODE_SENSE;
-    cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
-    cmd[2] = 0x2a;
-    cmd[4] = 128;
-    cmd[3] = cmd[5] = 0;
-    rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
-    
-    if (-EINVAL == rc) {
-        /* failed, drive has'nt this mode page */
-        scsi_CDs[i].cdi.speed      = 1;
-        /* disable speed select, drive probably can't do this either */
-        scsi_CDs[i].cdi.mask      |= CDC_SELECT_SPEED;
-	scsi_free(buffer, 512);
-	return;
-    }
-    
-    n = buffer[3]+4;
-    scsi_CDs[i].cdi.speed    = ((buffer[n+8] << 8) + buffer[n+9])/176;
-    scsi_CDs[i].readcd_known = 1;
-    scsi_CDs[i].readcd_cdda  = buffer[n+5] & 0x01;
-    /* print some capability bits */
-    printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n",i,
-    	((buffer[n+14] << 8) + buffer[n+15])/176,
-	scsi_CDs[i].cdi.speed,
-	buffer[n+3]&0x01 ? "writer " : "",   /* CD Writer */
-	buffer[n+2]&0x02 ? "cd/rw " : "",    /* can read rewriteable */
-	buffer[n+4]&0x20 ? "xa/form2 " : "", /* can read xa/from2 */
-	buffer[n+5]&0x01 ? "cdda " : "",     /* can read audio data */
-	loadmech[buffer[n+6]>>5]);
-    if ((buffer[n+6] >> 5) == 0)
-	/* caddy drives can't close tray... */
-        scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
-    if ((buffer[n+2] & 0x8) == 0)
-	/* not a DVD drive */
-	scsi_CDs[i].cdi.mask |= CDC_DVD;
-    if ((buffer[n+3] & 0x20) == 0)
-    	/* can't write DVD-RAM media */
-	scsi_CDs[i].cdi.mask |= CDC_DVD_RAM;
-    if ((buffer[n+3] & 0x10) == 0)
-    	/* can't write DVD-R media */
-	scsi_CDs[i].cdi.mask |= CDC_DVD_R;
-    if ((buffer[n+3] & 0x2) == 0)
-    	/* can't write CD-RW media */
-	scsi_CDs[i].cdi.mask |= CDC_CD_RW;
-    if ((buffer[n+3] & 0x1) == 0)
-    	/* can't write CD-R media */
-	scsi_CDs[i].cdi.mask |= CDC_CD_R;
+void get_capabilities(int i)
+{
+	unsigned char cmd[6];
+	unsigned char *buffer;
+	int rc, n;
+
+	static char *loadmech[] =
+	{
+		"caddy",
+		"tray",
+		"pop-up",
+		"",
+		"changer",
+		"changer",
+		"",
+		""
+	};
+
+	buffer = (unsigned char *) scsi_malloc(512);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+	cmd[2] = 0x2a;
+	cmd[4] = 128;
+	cmd[3] = cmd[5] = 0;
+	rc = sr_do_ioctl(i, cmd, buffer, 128, 1);
+
+	if (-EINVAL == rc) {
+		/* failed, drive has'nt this mode page */
+		scsi_CDs[i].cdi.speed = 1;
+		/* disable speed select, drive probably can't do this either */
+		scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED;
+		scsi_free(buffer, 512);
+		return;
+	}
+	n = buffer[3] + 4;
+	scsi_CDs[i].cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
+	scsi_CDs[i].readcd_known = 1;
+	scsi_CDs[i].readcd_cdda = buffer[n + 5] & 0x01;
+	/* print some capability bits */
+	printk("sr%i: scsi3-mmc drive: %dx/%dx %s%s%s%s%s\n", i,
+	       ((buffer[n + 14] << 8) + buffer[n + 15]) / 176,
+	       scsi_CDs[i].cdi.speed,
+	       buffer[n + 3] & 0x01 ? "writer " : "",	/* CD Writer */
+	       buffer[n + 2] & 0x02 ? "cd/rw " : "",	/* can read rewriteable */
+	       buffer[n + 4] & 0x20 ? "xa/form2 " : "",		/* can read xa/from2 */
+	       buffer[n + 5] & 0x01 ? "cdda " : "",	/* can read audio data */
+	       loadmech[buffer[n + 6] >> 5]);
+	if ((buffer[n + 6] >> 5) == 0)
+		/* caddy drives can't close tray... */
+		scsi_CDs[i].cdi.mask |= CDC_CLOSE_TRAY;
+	if ((buffer[n + 2] & 0x8) == 0)
+		/* not a DVD drive */
+		scsi_CDs[i].cdi.mask |= CDC_DVD;
+	if ((buffer[n + 3] & 0x20) == 0)
+		/* can't write DVD-RAM media */
+		scsi_CDs[i].cdi.mask |= CDC_DVD_RAM;
+	if ((buffer[n + 3] & 0x10) == 0)
+		/* can't write DVD-R media */
+		scsi_CDs[i].cdi.mask |= CDC_DVD_R;
+	if ((buffer[n + 3] & 0x2) == 0)
+		/* can't write CD-RW media */
+		scsi_CDs[i].cdi.mask |= CDC_CD_RW;
+	if ((buffer[n + 3] & 0x1) == 0)
+		/* can't write CD-R media */
+		scsi_CDs[i].cdi.mask |= CDC_CD_R;
 
-    scsi_free(buffer, 512);
+	scsi_free(buffer, 512);
 }
 
 /*
  * sr_packet() is the entry point for the generic commands generated
  * by the Uniform CD-ROM layer. 
-*/
+ */
 static int sr_packet(struct cdrom_device_info *cdi, struct cdrom_generic_command *cgc)
 {
 	Scsi_Cmnd *SCpnt;
@@ -1048,12 +1025,12 @@
 	DECLARE_MUTEX_LOCKED(sem);
 	unsigned long flags;
 	int stat;
-	
+
 	/* get the device */
 	SCpnt = scsi_allocate_device(NULL, device, 1);
 	if (SCpnt == NULL)
 		return -ENODEV;	/* this just doesn't seem right /axboe */
-	
+
 	/* set the LUN */
 	cgc->cmd[1] |= device->lun << 5;
 
@@ -1064,18 +1041,18 @@
 	SCpnt->cmd_len = 0;
 	SCpnt->request.sem = &sem;
 	spin_lock_irqsave(&io_request_lock, flags);
-	scsi_do_cmd (SCpnt, (void *)cgc->cmd, (void *)cgc->buffer, cgc->buflen,
-		     sr_init_done, SR_TIMEOUT, MAX_RETRIES);
+	scsi_do_cmd(SCpnt, (void *) cgc->cmd, (void *) cgc->buffer, cgc->buflen,
+		    sr_init_done, SR_TIMEOUT, MAX_RETRIES);
 	spin_unlock_irqrestore(&io_request_lock, flags);
 	down(&sem);
-	
+
 	stat = SCpnt->result;
 
 	/* release */
-	SCpnt->request.rq_dev = MKDEV(0,0);
+	SCpnt->request.rq_dev = MKDEV(0, 0);
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
-	
+
 	return stat;
 }
 
@@ -1083,159 +1060,162 @@
 
 static int sr_init()
 {
-    int i;
+	int i;
 
-    if(sr_template.dev_noticed == 0) return 0;
+	if (sr_template.dev_noticed == 0)
+		return 0;
 
-    if(!sr_registered) {
-	if (register_blkdev(MAJOR_NR,"sr",&cdrom_fops)) {
-	    printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
-	    return 1;
+	if (!sr_registered) {
+		if (register_blkdev(MAJOR_NR, "sr", &cdrom_fops)) {
+			printk("Unable to get major %d for SCSI-CD\n", MAJOR_NR);
+			return 1;
+		}
+		sr_registered++;
 	}
-	sr_registered++;
-    }
-
-
-    if (scsi_CDs) return 0;
-    sr_template.dev_max =
-            sr_template.dev_noticed + SR_EXTRA_DEVS;
-    scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
-    memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
+	if (scsi_CDs)
+		return 0;
+	sr_template.dev_max =
+	    sr_template.dev_noticed + SR_EXTRA_DEVS;
+	scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
+	memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
 
-    sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
-    memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
+	sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
+	memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
 
-    sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
-					 sizeof(int), GFP_ATOMIC);
+	sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
+						 sizeof(int), GFP_ATOMIC);
 
-    /*
-     * These are good guesses for the time being.
-     */
-    for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
-    blksize_size[MAJOR_NR] = sr_blocksizes;
-    return 0;
+	/*
+	 * These are good guesses for the time being.
+	 */
+	for (i = 0; i < sr_template.dev_max; i++)
+		sr_blocksizes[i] = 2048;
+	blksize_size[MAJOR_NR] = sr_blocksizes;
+	return 0;
 }
 
 void sr_finish()
 {
-    int i;
-    char name[6];
+	int i;
+	char name[6];
 
-    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-    blk_size[MAJOR_NR] = sr_sizes;
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blk_size[MAJOR_NR] = sr_sizes;
 
-    for (i = 0; i < sr_template.nr_dev; ++i)
-    {
-	/* If we have already seen this, then skip it.  Comes up
-	 * with loadable modules. */
-	if (scsi_CDs[i].capacity) continue;
-	scsi_CDs[i].capacity = 0x1fffff;
-	scsi_CDs[i].sector_size = 2048;  /* A guess, just in case */
-	scsi_CDs[i].needs_sector_size = 1;
-	scsi_CDs[i].device->changed = 1; /* force recheck CD type */
+	for (i = 0; i < sr_template.nr_dev; ++i) {
+		/* If we have already seen this, then skip it.  Comes up
+		 * with loadable modules. */
+		if (scsi_CDs[i].capacity)
+			continue;
+		scsi_CDs[i].capacity = 0x1fffff;
+		scsi_CDs[i].sector_size = 2048;		/* A guess, just in case */
+		scsi_CDs[i].needs_sector_size = 1;
+		scsi_CDs[i].device->changed = 1;	/* force recheck CD type */
 #if 0
-	/* seems better to leave this for later */
-	get_sectorsize(i);
-	printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
+		/* seems better to leave this for later */
+		get_sectorsize(i);
+		printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
 #endif
-	scsi_CDs[i].use = 1;
-	scsi_CDs[i].ten = 1;
-	scsi_CDs[i].remap = 1;
-      	scsi_CDs[i].readcd_known = 0;
-      	scsi_CDs[i].readcd_cdda  = 0;
-	sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
-
-	scsi_CDs[i].cdi.ops        = &sr_dops;
-	scsi_CDs[i].cdi.handle     = &scsi_CDs[i];
-	scsi_CDs[i].cdi.dev        = MKDEV(MAJOR_NR,i);
-	scsi_CDs[i].cdi.mask       = 0;
-        scsi_CDs[i].cdi.capacity   = 1;
-	get_capabilities(i);
-	sr_vendor_init(i);
-
-	sprintf(name, "sr%d", i);
-	strcpy(scsi_CDs[i].cdi.name, name);
-	register_cdrom(&scsi_CDs[i].cdi);
-    }
-
-
-    /* If our host adapter is capable of scatter-gather, then we increase
-     * the read-ahead to 16 blocks (32 sectors).  If not, we use
-     * a two block (4 sector) read ahead. */
-    if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
-	read_ahead[MAJOR_NR] = 32;  /* 32 sector read-ahead.  Always removable. */
-    else
-	read_ahead[MAJOR_NR] = 4;  /* 4 sector read-ahead */
+		scsi_CDs[i].use = 1;
+		scsi_CDs[i].ten = 1;
+		scsi_CDs[i].remap = 1;
+		scsi_CDs[i].readcd_known = 0;
+		scsi_CDs[i].readcd_cdda = 0;
+		sr_sizes[i] = scsi_CDs[i].capacity >> (BLOCK_SIZE_BITS - 9);
+
+		scsi_CDs[i].cdi.ops = &sr_dops;
+		scsi_CDs[i].cdi.handle = &scsi_CDs[i];
+		scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR, i);
+		scsi_CDs[i].cdi.mask = 0;
+		scsi_CDs[i].cdi.capacity = 1;
+		get_capabilities(i);
+		sr_vendor_init(i);
+
+		sprintf(name, "sr%d", i);
+		strcpy(scsi_CDs[i].cdi.name, name);
+		register_cdrom(&scsi_CDs[i].cdi);
+	}
+
+
+	/* If our host adapter is capable of scatter-gather, then we increase
+	 * the read-ahead to 16 blocks (32 sectors).  If not, we use
+	 * a two block (4 sector) read ahead. */
+	if (scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
+		read_ahead[MAJOR_NR] = 32;	/* 32 sector read-ahead.  Always removable. */
+	else
+		read_ahead[MAJOR_NR] = 4;	/* 4 sector read-ahead */
 
-    return;
+	return;
 }
 
 static void sr_detach(Scsi_Device * SDp)
 {
-    Scsi_CD * cpnt;
-    int i;
+	Scsi_CD *cpnt;
+	int i;
 
-    for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
-	if(cpnt->device == SDp) {
-	    kdev_t devi = MKDEV(MAJOR_NR, i);
-	    struct super_block * sb = get_super(devi);
-
-	    /*
-	     * Since the cdrom is read-only, no need to sync the device.
-	     * We should be kind to our buffer cache, however.
-	     */
-	    if (sb) invalidate_inodes(sb);
-	    invalidate_buffers(devi);
-
-	    /*
-	     * Reset things back to a sane state so that one can re-load a new
-	     * driver (perhaps the same one).
-	     */
-            unregister_cdrom(&(cpnt->cdi));
-	    cpnt->device = NULL;
-	    cpnt->capacity = 0;
-	    SDp->attached--;
-	    sr_template.nr_dev--;
-	    sr_template.dev_noticed--;
-	    sr_sizes[i] = 0;
-	    return;
-	}
-    return;
+	for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++)
+		if (cpnt->device == SDp) {
+			kdev_t devi = MKDEV(MAJOR_NR, i);
+			struct super_block *sb = get_super(devi);
+
+			/*
+			 * Since the cdrom is read-only, no need to sync the device.
+			 * We should be kind to our buffer cache, however.
+			 */
+			if (sb)
+				invalidate_inodes(sb);
+			invalidate_buffers(devi);
+
+			/*
+			 * Reset things back to a sane state so that one can re-load a new
+			 * driver (perhaps the same one).
+			 */
+			unregister_cdrom(&(cpnt->cdi));
+			cpnt->device = NULL;
+			cpnt->capacity = 0;
+			SDp->attached--;
+			sr_template.nr_dev--;
+			sr_template.dev_noticed--;
+			sr_sizes[i] = 0;
+			return;
+		}
+	return;
 }
 
 
 #ifdef MODULE
 
-int init_module(void) {
-        sr_template.module = &__this_module;
-        return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
+int init_module(void)
+{
+	sr_template.module = &__this_module;
+	return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
 }
 
-void cleanup_module( void)
+void cleanup_module(void)
 {
-    scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
-    unregister_blkdev(MAJOR_NR, "sr");
-    sr_registered--;
-    if(scsi_CDs != NULL) {
-	scsi_init_free((char *) scsi_CDs,
-		       (sr_template.dev_noticed + SR_EXTRA_DEVS)
-		       * sizeof(Scsi_CD));
-
-	scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
-        sr_sizes = NULL;
-
-	scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int));
-        sr_blocksizes = NULL;
-    }
-
-    blksize_size[MAJOR_NR] = NULL;
-    blk_dev[MAJOR_NR].request_fn = NULL;
-    blk_size[MAJOR_NR] = NULL;
-    read_ahead[MAJOR_NR] = 0;
+	scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
+	unregister_blkdev(MAJOR_NR, "sr");
+	sr_registered--;
+	if (scsi_CDs != NULL) {
+		scsi_init_free((char *) scsi_CDs,
+			       (sr_template.dev_noticed + SR_EXTRA_DEVS)
+			       * sizeof(Scsi_CD));
+
+		scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
+		sr_sizes = NULL;
 
-    sr_template.dev_max = 0;
+		scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int));
+		sr_blocksizes = NULL;
+	}
+	blksize_size[MAJOR_NR] = NULL;
+	blk_dev[MAJOR_NR].request_fn = NULL;
+	blk_size[MAJOR_NR] = NULL;
+	read_ahead[MAJOR_NR] = 0;
+
+	sr_template.dev_max = 0;
 }
-#endif /* MODULE */
+
+#endif				/* MODULE */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sr.h linux/drivers/scsi/sr.h
--- v2.3.16/linux/drivers/scsi/sr.h	Sat Jun 13 13:05:22 1998
+++ linux/drivers/scsi/sr.h	Sat Sep  4 10:48:46 1999
@@ -3,11 +3,11 @@
  *      CD-ROM disk driver header file
  *      
  *      adapted from:
- *	sd.h Copyright (C) 1992 Drew Eckhardt 
- *	SCSI disk driver header file by
- *		Drew Eckhardt 
+ *      sd.h Copyright (C) 1992 Drew Eckhardt 
+ *      SCSI disk driver header file by
+ *              Drew Eckhardt 
  *
- *	<drew@colorado.edu>
+ *      <drew@colorado.edu>
  *
  *       Modified by Eric Youngdale eric@aib.com to
  *       add scatter-gather, multiple outstanding request, and other
@@ -19,46 +19,45 @@
 
 #include "scsi.h"
 
-typedef struct
-	{
-	unsigned 	capacity;		/* size in blocks 			*/
-	unsigned 	sector_size;		/* size in bytes 			*/
-	Scsi_Device  	*device;
-        unsigned int    vendor;                 /* vendor code, see sr_vendor.c         */
-	unsigned long   ms_offset;              /* for reading multisession-CD's        */
-	unsigned char	sector_bit_size;	/* sector size = 2^sector_bit_size	*/
-	unsigned char	sector_bit_shift;	/* sectors/FS block = 2^sector_bit_shift*/
-	unsigned 	needs_sector_size:1;   	/* needs to get sector size */
-	unsigned 	ten:1;			/* support ten byte commands		*/
-	unsigned 	remap:1;		/* support remapping			*/
-	unsigned 	use:1;			/* is this device still supportable	*/
-        unsigned	xa_flag:1;              /* CD has XA sectors ? */
-	unsigned 	readcd_known:1;		/* drive supports READ_CD (0xbe) */
-	unsigned 	readcd_cdda:1;		/* reading audio data using READ_CD */
+typedef struct {
+	unsigned capacity;	/* size in blocks                       */
+	unsigned sector_size;	/* size in bytes                        */
+	Scsi_Device *device;
+	unsigned int vendor;	/* vendor code, see sr_vendor.c         */
+	unsigned long ms_offset;	/* for reading multisession-CD's        */
+	unsigned char sector_bit_size;	/* sector size = 2^sector_bit_size      */
+	unsigned char sector_bit_shift;		/* sectors/FS block = 2^sector_bit_shift */
+	unsigned needs_sector_size:1;	/* needs to get sector size */
+	unsigned ten:1;		/* support ten byte commands            */
+	unsigned remap:1;	/* support remapping                    */
+	unsigned use:1;		/* is this device still supportable     */
+	unsigned xa_flag:1;	/* CD has XA sectors ? */
+	unsigned readcd_known:1;	/* drive supports READ_CD (0xbe) */
+	unsigned readcd_cdda:1;	/* reading audio data using READ_CD */
 	struct cdrom_device_info cdi;
-	} Scsi_CD;
-	
-extern Scsi_CD * scsi_CDs;
-
-int sr_do_ioctl(int, unsigned char*, void*, unsigned, int);
-
-int sr_lock_door(struct cdrom_device_info*, int);
-int sr_tray_move(struct cdrom_device_info*, int);
-int sr_drive_status(struct cdrom_device_info*, int);
-int sr_disk_status(struct cdrom_device_info*);
-int sr_get_last_session(struct cdrom_device_info*, struct cdrom_multisession*);
-int sr_get_mcn(struct cdrom_device_info*, struct cdrom_mcn*);
-int sr_reset(struct cdrom_device_info*);
+} Scsi_CD;
+
+extern Scsi_CD *scsi_CDs;
+
+int sr_do_ioctl(int, unsigned char *, void *, unsigned, int);
+
+int sr_lock_door(struct cdrom_device_info *, int);
+int sr_tray_move(struct cdrom_device_info *, int);
+int sr_drive_status(struct cdrom_device_info *, int);
+int sr_disk_status(struct cdrom_device_info *);
+int sr_get_last_session(struct cdrom_device_info *, struct cdrom_multisession *);
+int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
+int sr_reset(struct cdrom_device_info *);
 int sr_select_speed(struct cdrom_device_info *cdi, int speed);
-int sr_audio_ioctl(struct cdrom_device_info*, unsigned int, void*);
-int sr_dev_ioctl(struct cdrom_device_info*, unsigned int, unsigned long);
+int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
+int sr_dev_ioctl(struct cdrom_device_info *, unsigned int, unsigned long);
 
 int sr_read_sector(int minor, int lba, int blksize, unsigned char *dest);
 int sr_is_xa(int minor);
 
 /* sr_vendor.c */
 void sr_vendor_init(int minor);
-int sr_cd_check(struct cdrom_device_info*);
+int sr_cd_check(struct cdrom_device_info *);
 int sr_set_blocklength(int minor, int blocklength);
 
 #endif
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c
--- v2.3.16/linux/drivers/scsi/sr_vendor.c	Mon May 10 13:01:21 1999
+++ linux/drivers/scsi/sr_vendor.c	Sat Sep  4 10:48:46 1999
@@ -60,8 +60,7 @@
 
 #define VENDOR_ID (scsi_CDs[minor].vendor)
 
-void
-sr_vendor_init(int minor)
+void sr_vendor_init(int minor)
 {
 #ifndef CONFIG_BLK_DEV_SR_VENDOR
 	VENDOR_ID = VENDOR_SCSI3;
@@ -104,8 +103,7 @@
 /* small handy function for switching block length using MODE SELECT,
  * used by sr_read_sector() */
 
-int
-sr_set_blocklength(int minor, int blocklength)
+int sr_set_blocklength(int minor, int blocklength)
 {
 	unsigned char           *buffer;    /* the buffer for the ioctl */
 	unsigned char		cmd[12];    /* the scsi-command */
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.3.16/linux/drivers/scsi/st.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/scsi/st.c	Sat Sep  4 10:48:46 1999
@@ -1,19 +1,19 @@
 /*
-  SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
-  file README.st for more information.
+   SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
+   file README.st for more information.
 
-  History:
-  Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
-  Contribution and ideas from several people including (in alphabetical
-  order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
-  Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
-
-  Copyright 1992 - 1999 Kai Makisara
-		 email Kai.Makisara@metla.fi
-
-  Last modified: Sat Aug  7 13:54:31 1999 by makisara@kai.makisara.local
-  Some small formal changes - aeb, 950809
-*/
+   History:
+   Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
+   Contribution and ideas from several people including (in alphabetical
+   order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
+   Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
+
+   Copyright 1992 - 1999 Kai Makisara
+   email Kai.Makisara@metla.fi
+
+   Last modified: Sat Aug  7 13:54:31 1999 by makisara@kai.makisara.local
+   Some small formal changes - aeb, 950809
+ */
 
 #include <linux/module.h>
 
@@ -67,14 +67,25 @@
 MODULE_PARM(max_buffers, "i");
 MODULE_PARM(max_sg_segs, "i");
 #else
+
 static struct st_dev_parm {
-    char *name;
-    int *val;
+	char *name;
+	int *val;
 } parms[] __initdata = {
-    {"buffer_kbs", &buffer_kbs},
-    {"write_threshold_kbs", &write_threshold_kbs},
-    {"max_buffers", &max_buffers},
-    {"max_sg_segs", &max_sg_segs}};
+	{
+		"buffer_kbs", &buffer_kbs
+	},
+	{
+		"write_threshold_kbs", &write_threshold_kbs
+	},
+	{
+		"max_buffers", &max_buffers
+	},
+	{
+		"max_sg_segs", &max_sg_segs
+	}
+};
+
 #endif
 
 
@@ -115,7 +126,7 @@
 static int st_max_buffers = ST_MAX_BUFFERS;
 static int st_max_sg_segs = ST_MAX_SG;
 
-static Scsi_Tape * scsi_tapes = NULL;
+static Scsi_Tape *scsi_tapes = NULL;
 
 static int modes_defined = FALSE;
 
@@ -130,142 +141,137 @@
 static int st_detect(Scsi_Device *);
 static void st_detach(Scsi_Device *);
 
-struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE,
-					     SCSI_TAPE_MAJOR, 0, 0, 0, 0,
-					     st_detect, st_init,
-					     NULL, st_attach, st_detach};
+struct Scsi_Device_Template st_template =
+{NULL, "tape", "st", NULL, TYPE_TAPE,
+ SCSI_TAPE_MAJOR, 0, 0, 0, 0,
+ st_detect, st_init,
+ NULL, st_attach, st_detach};
 
 static int st_compression(Scsi_Tape *, int);
 
 static int find_partition(struct inode *);
 static int update_partition(struct inode *);
 
-static int st_int_ioctl(struct inode * inode, unsigned int cmd_in,
+static int st_int_ioctl(struct inode *inode, unsigned int cmd_in,
 			unsigned long arg);
+
 
 
 
-
 /* Convert the result to success code */
-	static int
-st_chk_result(Scsi_Cmnd * SCpnt)
+static int st_chk_result(Scsi_Cmnd * SCpnt)
 {
-  int dev = TAPE_NR(SCpnt->request.rq_dev);
-  int result = SCpnt->result;
-  unsigned char * sense = SCpnt->sense_buffer, scode;
-#if DEBUG
-  const char *stp;
-#endif
-
-  if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
-    return 0;
-
-  if (driver_byte(result) & DRIVER_SENSE)
-      scode = sense[2] & 0x0f;
-  else {
-      sense[0] = 0;    /* We don't have sense data if this byte is zero */
-      scode = 0;
-  }
-
-#if DEBUG
-  if (debugging) {
-    printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
-	   dev, result,
-	   SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
-	   SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
-	   SCpnt->request_bufflen);
-    if (driver_byte(result) & DRIVER_SENSE)
-      print_sense("st", SCpnt);
-  }
-  else
-#endif
-  if (!(driver_byte(result) & DRIVER_SENSE) ||
-      ((sense[0] & 0x70) == 0x70 &&
-       scode != NO_SENSE &&
-       scode != RECOVERED_ERROR &&
-/*       scode != UNIT_ATTENTION && */
-       scode != BLANK_CHECK &&
-       scode != VOLUME_OVERFLOW &&
-       SCpnt->data_cmnd[0] != MODE_SENSE &&
-       SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
-    if (driver_byte(result) & DRIVER_SENSE) {
-      printk(KERN_WARNING "st%d: Error with sense data: ", dev);
-      print_sense("st", SCpnt);
-    }
-    else
-      printk(KERN_WARNING
-	     "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
-	     dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
-	     host_byte(result));
-  }
+	int dev = TAPE_NR(SCpnt->request.rq_dev);
+	int result = SCpnt->result;
+	unsigned char *sense = SCpnt->sense_buffer, scode;
+#if DEBUG
+	const char *stp;
+#endif
+
+	if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
+		return 0;
+
+	if (driver_byte(result) & DRIVER_SENSE)
+		scode = sense[2] & 0x0f;
+	else {
+		sense[0] = 0;	/* We don't have sense data if this byte is zero */
+		scode = 0;
+	}
 
-  if ((sense[0] & 0x70) == 0x70 &&
-      scode == RECOVERED_ERROR
+#if DEBUG
+	if (debugging) {
+		printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+		       dev, result,
+		       SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
+		       SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
+		       SCpnt->request_bufflen);
+		if (driver_byte(result) & DRIVER_SENSE)
+			print_sense("st", SCpnt);
+	} else
+#endif
+		if (!(driver_byte(result) & DRIVER_SENSE) ||
+		    ((sense[0] & 0x70) == 0x70 &&
+		     scode != NO_SENSE &&
+		     scode != RECOVERED_ERROR &&
+/*       scode != UNIT_ATTENTION && */
+		     scode != BLANK_CHECK &&
+		     scode != VOLUME_OVERFLOW &&
+		     SCpnt->data_cmnd[0] != MODE_SENSE &&
+		     SCpnt->data_cmnd[0] != TEST_UNIT_READY)) {		/* Abnormal conditions for tape */
+		if (driver_byte(result) & DRIVER_SENSE) {
+			printk(KERN_WARNING "st%d: Error with sense data: ", dev);
+			print_sense("st", SCpnt);
+		} else
+			printk(KERN_WARNING
+			       "st%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			       dev, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
+			       host_byte(result));
+	}
+	if ((sense[0] & 0x70) == 0x70 &&
+	    scode == RECOVERED_ERROR
 #if ST_RECOVERED_WRITE_FATAL
-      && SCpnt->data_cmnd[0] != WRITE_6
-      && SCpnt->data_cmnd[0] != WRITE_FILEMARKS
+	    && SCpnt->data_cmnd[0] != WRITE_6
+	    && SCpnt->data_cmnd[0] != WRITE_FILEMARKS
 #endif
-      ) {
-    scsi_tapes[dev].recover_count++;
-    scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
-#if DEBUG
-    if (debugging) {
-      if (SCpnt->data_cmnd[0] == READ_6)
-	stp = "read";
-      else if (SCpnt->data_cmnd[0] == WRITE_6)
-	stp = "write";
-      else
-	stp = "ioctl";
-      printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,
-	     scsi_tapes[dev].recover_count);
-    }
-#endif
-    if ((sense[2] & 0xe0) == 0)
-      return 0;
-  }
-  return (-EIO);
+	    ) {
+		scsi_tapes[dev].recover_count++;
+		scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT);
+#if DEBUG
+		if (debugging) {
+			if (SCpnt->data_cmnd[0] == READ_6)
+				stp = "read";
+			else if (SCpnt->data_cmnd[0] == WRITE_6)
+				stp = "write";
+			else
+				stp = "ioctl";
+			printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,
+			       scsi_tapes[dev].recover_count);
+		}
+#endif
+		if ((sense[2] & 0xe0) == 0)
+			return 0;
+	}
+	return (-EIO);
 }
 
 
 /* Wakeup from interrupt */
-	static void
-st_sleep_done (Scsi_Cmnd * SCpnt)
+static void st_sleep_done(Scsi_Cmnd * SCpnt)
 {
-  unsigned int st_nbr;
-  int remainder;
-  Scsi_Tape * STp;
-
-  if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) {
-    STp = &(scsi_tapes[st_nbr]);
-    if ((STp->buffer)->writing &&
-	(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	(SCpnt->sense_buffer[2] & 0x40)) {
-      /* EOM at write-behind, has all been written? */
-      if ((SCpnt->sense_buffer[0] & 0x80) != 0)
-	remainder = (SCpnt->sense_buffer[3] << 24) |
-	      (SCpnt->sense_buffer[4] << 16) |
-		(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
-      else
-	remainder = 0;
-      if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
-	  remainder > 0)
-	(STp->buffer)->last_result = SCpnt->result; /* Error */
-      else
-	(STp->buffer)->last_result = INT_MAX; /* OK */
-    }
-    else
-      (STp->buffer)->last_result = SCpnt->result;
-    SCpnt->request.rq_status = RQ_SCSI_DONE;
-    (STp->buffer)->last_SCpnt = SCpnt;
+	unsigned int st_nbr;
+	int remainder;
+	Scsi_Tape *STp;
+
+	if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < st_template.nr_dev) {
+		STp = &(scsi_tapes[st_nbr]);
+		if ((STp->buffer)->writing &&
+		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+		    (SCpnt->sense_buffer[2] & 0x40)) {
+			/* EOM at write-behind, has all been written? */
+			if ((SCpnt->sense_buffer[0] & 0x80) != 0)
+				remainder = (SCpnt->sense_buffer[3] << 24) |
+				    (SCpnt->sense_buffer[4] << 16) |
+				    (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+			else
+				remainder = 0;
+			if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
+			    remainder > 0)
+				(STp->buffer)->last_result = SCpnt->result;	/* Error */
+			else
+				(STp->buffer)->last_result = INT_MAX;	/* OK */
+		} else
+			(STp->buffer)->last_result = SCpnt->result;
+		SCpnt->request.rq_status = RQ_SCSI_DONE;
+		(STp->buffer)->last_SCpnt = SCpnt;
 
 #if DEBUG
-    STp->write_pending = 0;
+		STp->write_pending = 0;
 #endif
-    up(SCpnt->request.sem);
-  }
+		up(SCpnt->request.sem);
+	}
 #if DEBUG
-  else if (debugging)
-    printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr);
+	else if (debugging)
+		printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr);
 #endif
 }
 
@@ -273,2462 +279,2351 @@
 /* Do the scsi command. Waits until command performed if do_wait is true.
    Otherwise write_behind_check() is used to check that the command
    has finished. */
-	static Scsi_Cmnd *
-st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
-	   int timeout, int retries, int do_wait)
-{
-  unsigned long flags;
-  unsigned char *bp;
-
-  spin_lock_irqsave(&io_request_lock, flags);
-  if (SCpnt == NULL)
-    if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
-      printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
-      spin_unlock_irqrestore(&io_request_lock, flags);
-      return NULL;
-    }
-
-  cmd[1] |= (SCpnt->lun << 5) & 0xe0;
-  init_MUTEX_LOCKED(&STp->sem);
-  SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
-      (STp->buffer)->use_sg : 0;
-  if (SCpnt->use_sg) {
-      bp = (char *)&((STp->buffer)->sg[0]);
-      if ((STp->buffer)->sg_segs < SCpnt->use_sg)
-	  SCpnt->use_sg = (STp->buffer)->sg_segs;
-  }
-  else
-      bp = (STp->buffer)->b_data;
-  SCpnt->cmd_len = 0;
-  SCpnt->request.sem = &(STp->sem);
-  SCpnt->request.rq_status = RQ_SCSI_BUSY;
-  SCpnt->request.rq_dev = STp->devt;
-
-  scsi_do_cmd(SCpnt, (void *)cmd, bp, bytes,
-	      st_sleep_done, timeout, retries);
-  spin_unlock_irqrestore(&io_request_lock, flags);
-
-  if (do_wait) {
-      down(SCpnt->request.sem);
+static Scsi_Cmnd *
+ st_do_scsi(Scsi_Cmnd * SCpnt, Scsi_Tape * STp, unsigned char *cmd, int bytes,
+	    int timeout, int retries, int do_wait)
+{
+	unsigned long flags;
+	unsigned char *bp;
+
+	spin_lock_irqsave(&io_request_lock, flags);
+	if (SCpnt == NULL)
+		if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
+			printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+			spin_unlock_irqrestore(&io_request_lock, flags);
+			return NULL;
+		}
+	cmd[1] |= (SCpnt->lun << 5) & 0xe0;
+	init_MUTEX_LOCKED(&STp->sem);
+	SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+	    (STp->buffer)->use_sg : 0;
+	if (SCpnt->use_sg) {
+		bp = (char *) &((STp->buffer)->sg[0]);
+		if ((STp->buffer)->sg_segs < SCpnt->use_sg)
+			SCpnt->use_sg = (STp->buffer)->sg_segs;
+	} else
+		bp = (STp->buffer)->b_data;
+	SCpnt->cmd_len = 0;
+	SCpnt->request.sem = &(STp->sem);
+	SCpnt->request.rq_status = RQ_SCSI_BUSY;
+	SCpnt->request.rq_dev = STp->devt;
+
+	scsi_do_cmd(SCpnt, (void *) cmd, bp, bytes,
+		    st_sleep_done, timeout, retries);
+	spin_unlock_irqrestore(&io_request_lock, flags);
 
-      (STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
-  }
+	if (do_wait) {
+		down(SCpnt->request.sem);
 
-  return SCpnt;
+		(STp->buffer)->last_result_fatal = st_chk_result(SCpnt);
+	}
+	return SCpnt;
 }
 
 
 /* Handle the write-behind checking (downs the semaphore) */
-	static void
-write_behind_check(Scsi_Tape *STp)
+static void write_behind_check(Scsi_Tape * STp)
 {
-  ST_buffer * STbuffer;
-  ST_partstat * STps;
+	ST_buffer *STbuffer;
+	ST_partstat *STps;
 
-  STbuffer = STp->buffer;
+	STbuffer = STp->buffer;
 
 #if DEBUG
-  if (STp->write_pending)
-    STp->nbr_waits++;
-  else
-    STp->nbr_finished++;
+	if (STp->write_pending)
+		STp->nbr_waits++;
+	else
+		STp->nbr_finished++;
 #endif
 
-  down(&(STp->sem));
+	down(&(STp->sem));
 
-  (STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
-  scsi_release_command((STp->buffer)->last_SCpnt);
+	(STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
+	scsi_release_command((STp->buffer)->last_SCpnt);
 
-  if (STbuffer->writing < STbuffer->buffer_bytes)
+	if (STbuffer->writing < STbuffer->buffer_bytes)
 #if 0
-    memcpy(STbuffer->b_data,
-	   STbuffer->b_data + STbuffer->writing,
-	   STbuffer->buffer_bytes - STbuffer->writing);
+		memcpy(STbuffer->b_data,
+		       STbuffer->b_data + STbuffer->writing,
+		       STbuffer->buffer_bytes - STbuffer->writing);
 #else
-  printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n");
+		printk(KERN_WARNING "st: write_behind_check: something left in buffer!\n");
 #endif
-  STbuffer->buffer_bytes -= STbuffer->writing;
-  STps = &(STp->ps[STp->partition]);
-  if (STps->drv_block >= 0) {
-    if (STp->block_size == 0)
-      STps->drv_block++;
-    else
-      STps->drv_block += STbuffer->writing / STp->block_size;
-  }
-  STbuffer->writing = 0;
+	STbuffer->buffer_bytes -= STbuffer->writing;
+	STps = &(STp->ps[STp->partition]);
+	if (STps->drv_block >= 0) {
+		if (STp->block_size == 0)
+			STps->drv_block++;
+		else
+			STps->drv_block += STbuffer->writing / STp->block_size;
+	}
+	STbuffer->writing = 0;
 
-  return;
+	return;
 }
 
 
 /* Step over EOF if it has been inadvertently crossed (ioctl not used because
    it messes up the block number). */
-	static int
-cross_eof(Scsi_Tape *STp, int forward)
+static int cross_eof(Scsi_Tape * STp, int forward)
 {
-  Scsi_Cmnd *SCpnt;
-  unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt;
+	unsigned char cmd[10];
 
-  cmd[0] = SPACE;
-  cmd[1] = 0x01; /* Space FileMarks */
-  if (forward) {
-      cmd[2] = cmd[3] = 0;
-      cmd[4] = 1;
-  }
-  else
-      cmd[2] = cmd[3] = cmd[4] = 0xff;  /* -1 filemarks */
-  cmd[5] = 0;
-#if DEBUG
-  if (debugging)
-    printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
-	   TAPE_NR(STp->devt), forward ? "forward" : "backward");
-#endif
-
-  SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
-  if (!SCpnt)
-    return (-EBUSY);
-
-  scsi_release_command(SCpnt);
-  SCpnt = NULL;
-
-  if ((STp->buffer)->last_result != 0)
-    printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
-	   TAPE_NR(STp->devt), forward ? "forward" : "backward");
-
-  return (STp->buffer)->last_result_fatal;
-}
+	cmd[0] = SPACE;
+	cmd[1] = 0x01;		/* Space FileMarks */
+	if (forward) {
+		cmd[2] = cmd[3] = 0;
+		cmd[4] = 1;
+	} else
+		cmd[2] = cmd[3] = cmd[4] = 0xff;	/* -1 filemarks */
+	cmd[5] = 0;
+#if DEBUG
+	if (debugging)
+		printk(ST_DEB_MSG "st%d: Stepping over filemark %s.\n",
+		   TAPE_NR(STp->devt), forward ? "forward" : "backward");
+#endif
 
+	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
+	if (!SCpnt)
+		return (-EBUSY);
 
-/* Flush the write buffer (never need to write if variable blocksize). */
-	static int
-flush_write_buffer(Scsi_Tape *STp)
-{
-  int offset, transfer, blks;
-  int result;
-  unsigned char cmd[10];
-  Scsi_Cmnd *SCpnt;
-  ST_partstat * STps;
-
-  if ((STp->buffer)->writing) {
-    write_behind_check(STp);
-    if ((STp->buffer)->last_result_fatal) {
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n",
-	       TAPE_NR(STp->devt), (STp->buffer)->last_result);
-#endif
-      if ((STp->buffer)->last_result == INT_MAX)
-	return (-ENOSPC);
-      return (-EIO);
-    }
-  }
-
-  if (STp->block_size == 0)
-    return 0;
-
-  result = 0;
-  if (STp->dirty == 1) {
-
-    offset = (STp->buffer)->buffer_bytes;
-    transfer = ((offset + STp->block_size - 1) /
-		STp->block_size) * STp->block_size;
-#if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer);
-#endif
-    memset((STp->buffer)->b_data + offset, 0, transfer - offset);
-
-    memset(cmd, 0, 10);
-    cmd[0] = WRITE_6;
-    cmd[1] = 1;
-    blks = transfer / STp->block_size;
-    cmd[2] = blks >> 16;
-    cmd[3] = blks >> 8;
-    cmd[4] = blks;
-
-    SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES,
-		       TRUE);
-    if (!SCpnt)
-      return (-EBUSY);
-
-    STps = &(STp->ps[STp->partition]);
-    if ((STp->buffer)->last_result_fatal != 0) {
-      if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	  (SCpnt->sense_buffer[2] & 0x40) &&
-	  (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
-	STp->dirty = 0;
-	(STp->buffer)->buffer_bytes = 0;
-	result = (-ENOSPC);
-      }
-      else {
-	printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt));
-	result = (-EIO);
-      }
-      STps->drv_block = (-1);
-    }
-    else {
-      if (STps->drv_block >= 0)
-	STps->drv_block += blks;
-      STp->dirty = 0;
-      (STp->buffer)->buffer_bytes = 0;
-    }
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-  }
-  return result;
-}
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
 
+	if ((STp->buffer)->last_result != 0)
+		printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
+		   TAPE_NR(STp->devt), forward ? "forward" : "backward");
 
-/* Flush the tape buffer. The tape will be positioned correctly unless
-   seek_next is true. */
-	static int
-flush_buffer(struct inode * inode, struct file * filp, int seek_next)
-{
-  int backspace, result;
-  Scsi_Tape * STp;
-  ST_buffer * STbuffer;
-  ST_partstat * STps;
-  int dev = TAPE_NR(inode->i_rdev);
-
-  STp = &(scsi_tapes[dev]);
-  STbuffer = STp->buffer;
-
-  /*
-   * If there was a bus reset, block further access
-   * to this device.
-   */
-  if( STp->device->was_reset )
-    return (-EIO);
-
-  if (STp->ready != ST_READY)
-    return 0;
-
-  STps = &(STp->ps[STp->partition]);
-  if (STps->rw == ST_WRITING)  /* Writing */
-    return flush_write_buffer(STp);
-
-  if (STp->block_size == 0)
-    return 0;
-
-  backspace = ((STp->buffer)->buffer_bytes +
-    (STp->buffer)->read_pointer) / STp->block_size -
-      ((STp->buffer)->read_pointer + STp->block_size - 1) /
-	STp->block_size;
-  (STp->buffer)->buffer_bytes = 0;
-  (STp->buffer)->read_pointer = 0;
-  result = 0;
-  if (!seek_next) {
-    if (STps->eof == ST_FM_HIT) {
-      result = cross_eof(STp, FALSE); /* Back over the EOF hit */
-      if (!result)
-	  STps->eof = ST_NOEOF;
-      else {
-	  if (STps->drv_file >= 0)
-	      STps->drv_file++;
-	  STps->drv_block = 0;
-      }
-    }
-    if (!result && backspace > 0)
-      result = st_int_ioctl(inode, MTBSR, backspace);
-  }
-  else if (STps->eof == ST_FM_HIT) {
-    if (STps->drv_file >= 0)
-	STps->drv_file++;
-    STps->drv_block = 0;
-    STps->eof = ST_NOEOF;
-  }
-
-  return result;
-
-}
-
-/* Set the mode parameters */
-	static int
-set_mode_densblk(struct inode * inode, Scsi_Tape *STp, ST_mode *STm)
-{
-    int set_it = FALSE;
-    unsigned long arg;
-    int dev = TAPE_NR(inode->i_rdev);
-
-    if (!STp->density_changed &&
-	STm->default_density >= 0 &&
-	STm->default_density != STp->density) {
-      arg = STm->default_density;
-      set_it = TRUE;
-    }
-    else
-      arg = STp->density;
-    arg <<= MT_ST_DENSITY_SHIFT;
-    if (!STp->blksize_changed &&
-	STm->default_blksize >= 0 &&
-	STm->default_blksize != STp->block_size) {
-      arg |= STm->default_blksize;
-      set_it = TRUE;
-    }
-    else
-      arg |= STp->block_size;
-    if (set_it &&
-	st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) {
-      printk(KERN_WARNING
-	     "st%d: Can't set default block size to %d bytes and density %x.\n",
-	     dev, STm->default_blksize, STm->default_density);
-      if (modes_defined)
-	return (-EINVAL);
-    }
-    return 0;
+	return (STp->buffer)->last_result_fatal;
 }
 
-
-/* Open the device */
-	static int
-scsi_tape_open(struct inode * inode, struct file * filp)
+
+/* Flush the write buffer (never need to write if variable blocksize). */
+static int flush_write_buffer(Scsi_Tape * STp)
 {
-    unsigned short flags;
-    int i, need_dma_buffer, new_session = FALSE;
-    unsigned char cmd[10];
-    Scsi_Cmnd * SCpnt;
-    Scsi_Tape * STp;
-    ST_mode * STm;
-    ST_partstat * STps;
-    int dev = TAPE_NR(inode->i_rdev);
-    int mode = TAPE_MODE(inode->i_rdev);
-
-    if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
-      return (-ENXIO);
-
-    if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) ) {
-        return -ENXIO;
-    }
-
-    STp = &(scsi_tapes[dev]);
-    if (STp->in_use) {
-#if DEBUG
-      printk(ST_DEB_MSG "st%d: Device already in use.\n", dev);
-#endif
-      return (-EBUSY);
-    }
-    STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
-
-    if (mode != STp->current_mode) {
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
-	       dev, STp->current_mode, mode);
-#endif
-      new_session = TRUE;
-      STp->current_mode = mode;
-    }
-    STm = &(STp->modes[STp->current_mode]);
-
-    /* Allocate a buffer for this user */
-    need_dma_buffer = STp->restr_dma;
-    for (i=0; i < st_nbr_buffers; i++)
-      if (!st_buffers[i]->in_use &&
-	  (!need_dma_buffer || st_buffers[i]->dma))
-	break;
-    if (i >= st_nbr_buffers) {
-      STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
-      if (STp->buffer == NULL) {
-	printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
-	return (-EBUSY);
-      }
-    }
-    else
-      STp->buffer = st_buffers[i];
-    (STp->buffer)->in_use = 1;
-    (STp->buffer)->writing = 0;
-    (STp->buffer)->last_result_fatal = 0;
-    (STp->buffer)->use_sg = STp->device->host->sg_tablesize;
-
-    /* Compute the usable buffer size for this SCSI adapter */
-    if (!(STp->buffer)->use_sg)
-	(STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
-    else {
-	for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
-		 i < (STp->buffer)->sg_segs; i++)
-	    (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
-    }
-
-    flags = filp->f_flags;
-    STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
-
-    STp->dirty = 0;
-    for (i=0; i < ST_NBR_PARTITIONS; i++) {
-	STps = &(STp->ps[i]);
-	STps->rw = ST_IDLE;
-    }
-    STp->ready = ST_READY;
-    STp->recover_count = 0;
-#if DEBUG
-    STp->nbr_waits = STp->nbr_finished = 0;
-#endif
-
-    if (scsi_tapes[dev].device->host->hostt->module)
-	__MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-    if(st_template.module)
-	__MOD_INC_USE_COUNT(st_template.module);
-
-    memset ((void *) &cmd[0], 0, 10);
-    cmd[0] = TEST_UNIT_READY;
-
-    SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
-		       TRUE);
-    if (!SCpnt) {
-	if (scsi_tapes[dev].device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-	if(st_template.module)
-	    __MOD_DEC_USE_COUNT(st_template.module);
-	return (-EBUSY);
-    }
-
-    if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
-      memset ((void *) &cmd[0], 0, 10);
-      cmd[0] = TEST_UNIT_READY;
-
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
-			 TRUE);
-
-      (STp->device)->was_reset = 0;
-      STp->partition = STp->new_partition = 0;
-      if (STp->can_partitions)
-	STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
-      for (i=0; i < ST_NBR_PARTITIONS; i++) {
-	  STps = &(STp->ps[i]);
-	  STps->rw = ST_IDLE;
-	  STps->eof = ST_NOEOF;
-	  STps->at_sm = 0;
-	  STps->last_block_valid = FALSE;
-	  STps->drv_block = 0;
-	  STps->drv_file = 0 ;
-      }
-      new_session = TRUE;
-    }
-
-    if ((STp->buffer)->last_result_fatal != 0) {
-      if ((STp->device)->scsi_level >= SCSI_2 &&
-	  (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	  (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
-	  SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */
-	STp->ready = ST_NO_TAPE;
-      } else
-	STp->ready = ST_NOT_READY;
-      scsi_release_command(SCpnt);
-      SCpnt = NULL;
-      STp->density = 0;   	/* Clear the erroneous "residue" */
-      STp->write_prot = 0;
-      STp->block_size = 0;
-      STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
-      STp->partition = STp->new_partition = 0;
-      STp->door_locked = ST_UNLOCKED;
-      STp->in_use = 1;
-      return 0;
-    }
-
-    if (STp->omit_blklims)
-      STp->min_block = STp->max_block = (-1);
-    else {
-      memset ((void *) &cmd[0], 0, 10);
-      cmd[0] = READ_BLOCK_LIMITS;
-
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE);
-
-      if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
-	STp->max_block = ((STp->buffer)->b_data[1] << 16) |
-	  ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
-	STp->min_block = ((STp->buffer)->b_data[4] << 8) |
-	  (STp->buffer)->b_data[5];
+	int offset, transfer, blks;
+	int result;
+	unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt;
+	ST_partstat *STps;
+
+	if ((STp->buffer)->writing) {
+		write_behind_check(STp);
+		if ((STp->buffer)->last_result_fatal) {
 #if DEBUG
-	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
-		 STp->max_block);
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n",
+				       TAPE_NR(STp->devt), (STp->buffer)->last_result);
 #endif
-      }
-      else {
-	STp->min_block = STp->max_block = (-1);
+			if ((STp->buffer)->last_result == INT_MAX)
+				return (-ENOSPC);
+			return (-EIO);
+		}
+	}
+	if (STp->block_size == 0)
+		return 0;
+
+	result = 0;
+	if (STp->dirty == 1) {
+
+		offset = (STp->buffer)->buffer_bytes;
+		transfer = ((offset + STp->block_size - 1) /
+			    STp->block_size) * STp->block_size;
 #if DEBUG
-	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer);
 #endif
-      }
-    }
+		memset((STp->buffer)->b_data + offset, 0, transfer - offset);
+
+		memset(cmd, 0, 10);
+		cmd[0] = WRITE_6;
+		cmd[1] = 1;
+		blks = transfer / STp->block_size;
+		cmd[2] = blks >> 16;
+		cmd[3] = blks >> 8;
+		cmd[4] = blks;
+
+		SCpnt = st_do_scsi(NULL, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES,
+				   TRUE);
+		if (!SCpnt)
+			return (-EBUSY);
+
+		STps = &(STp->ps[STp->partition]);
+		if ((STp->buffer)->last_result_fatal != 0) {
+			if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+			    (SCpnt->sense_buffer[2] & 0x40) &&
+			    (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
+				STp->dirty = 0;
+				(STp->buffer)->buffer_bytes = 0;
+				result = (-ENOSPC);
+			} else {
+				printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt));
+				result = (-EIO);
+			}
+			STps->drv_block = (-1);
+		} else {
+			if (STps->drv_block >= 0)
+				STps->drv_block += blks;
+			STp->dirty = 0;
+			(STp->buffer)->buffer_bytes = 0;
+		}
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+	}
+	return result;
+}
 
-    memset ((void *) &cmd[0], 0, 10);
-    cmd[0] = MODE_SENSE;
-    cmd[4] = 12;
 
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
+/* Flush the tape buffer. The tape will be positioned correctly unless
+   seek_next is true. */
+static int flush_buffer(struct inode *inode, struct file *filp, int seek_next)
+{
+	int backspace, result;
+	Scsi_Tape *STp;
+	ST_buffer *STbuffer;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	STp = &(scsi_tapes[dev]);
+	STbuffer = STp->buffer;
+
+	/*
+	 * If there was a bus reset, block further access
+	 * to this device.
+	 */
+	if (STp->device->was_reset)
+		return (-EIO);
 
-    if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev);
-#endif
-      STp->block_size = ST_DEFAULT_BLOCK;  /* Educated guess (?) */
-      (STp->buffer)->last_result_fatal = 0;  /* Prevent error propagation */
-      STp->drv_write_prot = 0;
-    }
-    else {
+	if (STp->ready != ST_READY)
+		return 0;
 
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
-	       dev,
-	       (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
-	       (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]);
-#endif
+	STps = &(STp->ps[STp->partition]);
+	if (STps->rw == ST_WRITING)	/* Writing */
+		return flush_write_buffer(STp);
 
-      if ((STp->buffer)->b_data[3] >= 8) {
-	STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
-	STp->density = (STp->buffer)->b_data[4];
-	STp->block_size = (STp->buffer)->b_data[9] * 65536 +
-	  (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
-#if DEBUG
-	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n",
-		 dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
-		 (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
-		 STp->drv_buffer);
-#endif
-      }
-
-      if (STp->block_size > (STp->buffer)->buffer_size &&
-	  !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
-	printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
-	       STp->block_size);
-	scsi_release_command(SCpnt);
-	(STp->buffer)->in_use = 0;
-	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-	if(st_template.module)
-	    __MOD_DEC_USE_COUNT(st_template.module);
-	return (-EIO);
-      }
-      STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
-    }
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if (STp->block_size > 0)
-      (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size;
-    else
-      (STp->buffer)->buffer_blocks = 1;
-    (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
-
-#if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
-	     STp->block_size, (STp->buffer)->buffer_size,
-	     (STp->buffer)->buffer_blocks);
-#endif
-
-    if (STp->drv_write_prot) {
-      STp->write_prot = 1;
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Write protected\n", dev);
-#endif
-      if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
-	(STp->buffer)->in_use = 0;
-	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-	if(st_template.module)
-	    __MOD_DEC_USE_COUNT(st_template.module);
-	return (-EROFS);
-      }
-    }
-
-    if (STp->can_partitions && STp->nbr_partitions < 1) {
-      /* This code is reached when the device is opened for the first time
-	 after the driver has been initialized with tape in the drive and the
-	 partition support has been enabled. */
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev);
-#endif
-      if ((STp->partition = find_partition(inode)) < 0) {
-	(STp->buffer)->in_use = 0;
-	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-	if(st_template.module)
-	    __MOD_DEC_USE_COUNT(st_template.module);
-	return STp->partition;
-      }
-      STp->new_partition = STp->partition;
-      STp->nbr_partitions = 1;  /* This guess will be updated when necessary */
-    }
-
-    if (new_session) {  /* Change the drive parameters for the new mode */
-      STp->density_changed = STp->blksize_changed = FALSE;
-      STp->compression_changed = FALSE;
-      if (!(STm->defaults_for_writes) &&
-	  (i = set_mode_densblk(inode, STp, STm)) < 0) {
-	(STp->buffer)->in_use = 0;
-	STp->buffer = NULL;
-	if (scsi_tapes[dev].device->host->hostt->module)
-	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-	if(st_template.module)
-	    __MOD_DEC_USE_COUNT(st_template.module);
-	return i;
-      }
-      if (STp->default_drvbuffer != 0xff) {
-	if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
-	  printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n",
-		 dev, STp->default_drvbuffer);
-      }
-    }
+	if (STp->block_size == 0)
+		return 0;
 
-    STp->in_use = 1;
+	backspace = ((STp->buffer)->buffer_bytes +
+		     (STp->buffer)->read_pointer) / STp->block_size -
+	    ((STp->buffer)->read_pointer + STp->block_size - 1) /
+	    STp->block_size;
+	(STp->buffer)->buffer_bytes = 0;
+	(STp->buffer)->read_pointer = 0;
+	result = 0;
+	if (!seek_next) {
+		if (STps->eof == ST_FM_HIT) {
+			result = cross_eof(STp, FALSE);		/* Back over the EOF hit */
+			if (!result)
+				STps->eof = ST_NOEOF;
+			else {
+				if (STps->drv_file >= 0)
+					STps->drv_file++;
+				STps->drv_block = 0;
+			}
+		}
+		if (!result && backspace > 0)
+			result = st_int_ioctl(inode, MTBSR, backspace);
+	} else if (STps->eof == ST_FM_HIT) {
+		if (STps->drv_file >= 0)
+			STps->drv_file++;
+		STps->drv_block = 0;
+		STps->eof = ST_NOEOF;
+	}
+	return result;
 
-    return 0;
 }
-
 
-/* Flush the tape buffer before close */
-	static int
-scsi_tape_flush(struct file * filp)
+/* Set the mode parameters */
+static int set_mode_densblk(struct inode *inode, Scsi_Tape * STp, ST_mode * STm)
 {
-    int result = 0, result2;
-    static unsigned char cmd[10];
-    Scsi_Cmnd * SCpnt;
-    Scsi_Tape * STp;
-    ST_mode * STm;
-    ST_partstat * STps;
-
-    struct inode *inode = filp->f_dentry->d_inode;
-    kdev_t devt = inode->i_rdev;
-    int dev;
-
-    if (file_count(filp) > 1)
+	int set_it = FALSE;
+	unsigned long arg;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	if (!STp->density_changed &&
+	    STm->default_density >= 0 &&
+	    STm->default_density != STp->density) {
+		arg = STm->default_density;
+		set_it = TRUE;
+	} else
+		arg = STp->density;
+	arg <<= MT_ST_DENSITY_SHIFT;
+	if (!STp->blksize_changed &&
+	    STm->default_blksize >= 0 &&
+	    STm->default_blksize != STp->block_size) {
+		arg |= STm->default_blksize;
+		set_it = TRUE;
+	} else
+		arg |= STp->block_size;
+	if (set_it &&
+	    st_int_ioctl(inode, SET_DENS_AND_BLK, arg)) {
+		printk(KERN_WARNING
+		       "st%d: Can't set default block size to %d bytes and density %x.\n",
+		       dev, STm->default_blksize, STm->default_density);
+		if (modes_defined)
+			return (-EINVAL);
+	}
 	return 0;
+}
+
+
+/* Open the device */
+static int scsi_tape_open(struct inode *inode, struct file *filp)
+{
+	unsigned short flags;
+	int i, need_dma_buffer, new_session = FALSE;
+	unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+	int mode = TAPE_MODE(inode->i_rdev);
 
-    dev = TAPE_NR(devt);
-    STp = &(scsi_tapes[dev]);
-    STm = &(STp->modes[STp->current_mode]);
-    STps = &(STp->ps[STp->partition]);
+	if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
+		return (-ENXIO);
+
+	if (!scsi_block_when_processing_errors(scsi_tapes[dev].device)) {
+		return -ENXIO;
+	}
+	STp = &(scsi_tapes[dev]);
+	if (STp->in_use) {
+#if DEBUG
+		printk(ST_DEB_MSG "st%d: Device already in use.\n", dev);
+#endif
+		return (-EBUSY);
+	}
+	STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
 
-    if (STp->can_partitions &&
-	(result = update_partition(inode)) < 0) {
+	if (mode != STp->current_mode) {
 #if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n",
+			       dev, STp->current_mode, mode);
 #endif
-      goto out;
-    }
+		new_session = TRUE;
+		STp->current_mode = mode;
+	}
+	STm = &(STp->modes[STp->current_mode]);
 
-    if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+	/* Allocate a buffer for this user */
+	need_dma_buffer = STp->restr_dma;
+	for (i = 0; i < st_nbr_buffers; i++)
+		if (!st_buffers[i]->in_use &&
+		    (!need_dma_buffer || st_buffers[i]->dma))
+			break;
+	if (i >= st_nbr_buffers) {
+		STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
+		if (STp->buffer == NULL) {
+			printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
+			return (-EBUSY);
+		}
+	} else
+		STp->buffer = st_buffers[i];
+	(STp->buffer)->in_use = 1;
+	(STp->buffer)->writing = 0;
+	(STp->buffer)->last_result_fatal = 0;
+	(STp->buffer)->use_sg = STp->device->host->sg_tablesize;
+
+	/* Compute the usable buffer size for this SCSI adapter */
+	if (!(STp->buffer)->use_sg)
+		(STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
+	else {
+		for (i = 0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
+		     i < (STp->buffer)->sg_segs; i++)
+			(STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
+	}
 
-      result = flush_write_buffer(STp);
+	flags = filp->f_flags;
+	STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
 
+	STp->dirty = 0;
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(STp->ps[i]);
+		STps->rw = ST_IDLE;
+	}
+	STp->ready = ST_READY;
+	STp->recover_count = 0;
 #if DEBUG
-      if (debugging) {
-	printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
-	       dev, (long)(filp->f_pos));
-	printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
-	       dev, STp->nbr_waits, STp->nbr_finished);
-      }
+	STp->nbr_waits = STp->nbr_finished = 0;
 #endif
 
-      if (result == 0 || result == (-ENOSPC)) {
+	if (scsi_tapes[dev].device->host->hostt->module)
+		__MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if (st_template.module)
+		__MOD_INC_USE_COUNT(st_template.module);
 
-	memset(cmd, 0, 10);
-	cmd[0] = WRITE_FILEMARKS;
-	cmd[4] = 1 + STp->two_fm;
+	memset((void *) &cmd[0], 0, 10);
+	cmd[0] = TEST_UNIT_READY;
 
-	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES,
+	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
 			   TRUE);
-	if (!SCpnt)
-	  goto out;
-
-	if ((STp->buffer)->last_result_fatal != 0 &&
-	    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
-	     (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
-	     ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
-	      (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
-	       SCpnt->sense_buffer[5] |
-	       SCpnt->sense_buffer[6]) == 0))) {
-	    /* Filter out successful write at EOM */
-	    scsi_release_command(SCpnt);
-	    SCpnt = NULL;
-	    printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
-	    if (result == 0)
-		result = (-EIO);
+	if (!SCpnt) {
+		if (scsi_tapes[dev].device->host->hostt->module)
+			__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+		if (st_template.module)
+			__MOD_DEC_USE_COUNT(st_template.module);
+		return (-EBUSY);
 	}
-	else {
-	  scsi_release_command(SCpnt);
-	  SCpnt = NULL;
-	  if (STps->drv_file >= 0)
-	      STps->drv_file++ ;
-	  STps->drv_block = 0;
-	  if (STp->two_fm)
-	    cross_eof(STp, FALSE);
-	  STps->eof = ST_FM;
-	}
-      }
-
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
-	       dev, cmd[4]);
-#endif
-    }
-    else if (!STp->rew_at_close) {
-	STps = &(STp->ps[STp->partition]);
-	if (!STm->sysv || STps->rw != ST_READING) {
-	    if (STp->can_bsr)
-		result = flush_buffer(inode, filp, 0);
-	    else if (STps->eof == ST_FM_HIT) {
-		result = cross_eof(STp, FALSE);
-		if (result) {
-		    if (STps->drv_file >= 0)
-			STps->drv_file++;
-		    STps->drv_block = 0;
-		    STps->eof = ST_FM;
+	if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	    (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {	/* New media? */
+		memset((void *) &cmd[0], 0, 10);
+		cmd[0] = TEST_UNIT_READY;
+
+		SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
+				   TRUE);
+
+		(STp->device)->was_reset = 0;
+		STp->partition = STp->new_partition = 0;
+		if (STp->can_partitions)
+			STp->nbr_partitions = 1;	/* This guess will be updated later if necessary */
+		for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+			STps = &(STp->ps[i]);
+			STps->rw = ST_IDLE;
+			STps->eof = ST_NOEOF;
+			STps->at_sm = 0;
+			STps->last_block_valid = FALSE;
+			STps->drv_block = 0;
+			STps->drv_file = 0;
 		}
-		else
-		    STps->eof = ST_NOEOF;
-	    }
+		new_session = TRUE;
 	}
-	else if ((STps->eof == ST_NOEOF &&
-		  !(result = cross_eof(STp, TRUE))) ||
-		 STps->eof == ST_FM_HIT) {
-	    if (STps->drv_file >= 0)
-		STps->drv_file++;
-	    STps->drv_block = 0;
-	    STps->eof = ST_FM;
-	}
-    }
-
-out:
-    if (STp->rew_at_close) {
-      result2 = st_int_ioctl(inode, MTREW, 1);
-      if (result == 0)
-	  result = result2;
-    }
-
-    return result;
-}
-
-
-/* Close the device and release it */
-	static int
-scsi_tape_close(struct inode * inode, struct file * filp)
-{
-    int result = 0;
-    Scsi_Tape * STp;
-
-    kdev_t devt = inode->i_rdev;
-    int dev;
-
-    dev = TAPE_NR(devt);
-    STp = &(scsi_tapes[dev]);
-
-    if (STp->door_locked == ST_LOCKED_AUTO)
-      st_int_ioctl(inode, MTUNLOCK, 0);
+	if ((STp->buffer)->last_result_fatal != 0) {
+		if ((STp->device)->scsi_level >= SCSI_2 &&
+		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+		    (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
+		    SCpnt->sense_buffer[12] == 0x3a) {	/* Check ASC */
+			STp->ready = ST_NO_TAPE;
+		} else
+			STp->ready = ST_NOT_READY;
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+		STp->density = 0;	/* Clear the erroneous "residue" */
+		STp->write_prot = 0;
+		STp->block_size = 0;
+		STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+		STp->partition = STp->new_partition = 0;
+		STp->door_locked = ST_UNLOCKED;
+		STp->in_use = 1;
+		return 0;
+	}
+	if (STp->omit_blklims)
+		STp->min_block = STp->max_block = (-1);
+	else {
+		memset((void *) &cmd[0], 0, 10);
+		cmd[0] = READ_BLOCK_LIMITS;
 
-    if (STp->buffer != NULL) {
-      normalize_buffer(STp->buffer);
-      (STp->buffer)->in_use = 0;
-    }
+		SCpnt = st_do_scsi(SCpnt, STp, cmd, 6, STp->timeout, MAX_READY_RETRIES, TRUE);
 
-    STp->in_use = 0;
-    if (scsi_tapes[dev].device->host->hostt->module)
-	__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-    if(st_template.module)
-	__MOD_DEC_USE_COUNT(st_template.module);
+		if (!SCpnt->result && !SCpnt->sense_buffer[0]) {
+			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
+			    ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
+			STp->min_block = ((STp->buffer)->b_data[4] << 8) |
+			    (STp->buffer)->b_data[5];
+#if DEBUG
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
+				       STp->max_block);
+#endif
+		} else {
+			STp->min_block = STp->max_block = (-1);
+#if DEBUG
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev);
+#endif
+		}
+	}
 
-    return result;
-}
+	memset((void *) &cmd[0], 0, 10);
+	cmd[0] = MODE_SENSE;
+	cmd[4] = 12;
 
-
-/* Write command */
-static ssize_t
-st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
-{
-    struct inode *inode = filp->f_dentry->d_inode;
-    ssize_t total;
-    ssize_t i, do_count, blks, retval, transfer;
-    int write_threshold;
-    int doing_write = 0;
-    static unsigned char cmd[10];
-    const char *b_point;
-    Scsi_Cmnd * SCpnt = NULL;
-    Scsi_Tape * STp;
-    ST_mode * STm;
-    ST_partstat * STps;
-    int dev = TAPE_NR(inode->i_rdev);
-
-    STp = &(scsi_tapes[dev]);
-
-    /*
-     * If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.
-     */
-    if( !scsi_block_when_processing_errors(STp->device) ) {
-        return -ENXIO;
-    }
-    
-    if (ppos != &filp->f_pos) {
-      /* "A request was outside the capabilities of the device." */
-      return -ENXIO;
-    }
-
-    if (STp->ready != ST_READY) {
-      if (STp->ready == ST_NO_TAPE)
-	return (-ENOMEDIUM);
-      else
-        return (-EIO);
-    }
-    STm = &(STp->modes[STp->current_mode]);
-    if (!STm->defined)
-      return (-ENXIO);
-    if (count == 0)
-      return 0;
-
-    /*
-     * If there was a bus reset, block further access
-     * to this device.
-     */
-    if( STp->device->was_reset )
-      return (-EIO);
-
-#if DEBUG
-    if (!STp->in_use) {
-      printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
-      return (-EIO);
-    }
-#endif
-
-    /* Write must be integral number of blocks */
-    if (STp->block_size != 0 && (count % STp->block_size) != 0) {
-	printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n",
-	       dev);
-	return (-EIO);
-    }
+	SCpnt = st_do_scsi(SCpnt, STp, cmd, 12, STp->timeout, MAX_READY_RETRIES, TRUE);
 
-    if (STp->can_partitions &&
-	(retval = update_partition(inode)) < 0)
-      return retval;
-    STps = &(STp->ps[STp->partition]);
-
-    if (STp->write_prot)
-      return (-EACCES);
-
-    if (STp->block_size == 0 &&
-       count > (STp->buffer)->buffer_size &&
-       !enlarge_buffer(STp->buffer, count, STp->restr_dma))
-      return (-EOVERFLOW);
-
-    if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
-       !st_int_ioctl(inode, MTLOCK, 0))
-      STp->door_locked = ST_LOCKED_AUTO;
-
-    if (STps->rw == ST_READING) {
-      retval = flush_buffer(inode, filp, 0);
-      if (retval)
-	return retval;
-      STps->rw = ST_WRITING;
-    }
-    else if (STps->rw != ST_WRITING &&
-	     STps->drv_file == 0 && STps->drv_block == 0) {
-      if ((retval = set_mode_densblk(inode, STp, STm)) < 0)
-	return retval;
-      if (STm->default_compression != ST_DONT_TOUCH &&
-	  !(STp->compression_changed)) {
-	if (st_compression(STp, (STm->default_compression == ST_YES))) {
-	  printk(KERN_WARNING "st%d: Can't set default compression.\n",
-		 dev);
-	  if (modes_defined)
-	    return (-EINVAL);
-	}
-      }
-    }
-
-    if ((STp->buffer)->writing) {
-      write_behind_check(STp);
-      if ((STp->buffer)->last_result_fatal) {
+	if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
-	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev,
-		 (STp->buffer)->last_result);
-#endif
-	if ((STp->buffer)->last_result == INT_MAX)
-	  STps->eof = ST_EOM_OK;
-	else
-	  STps->eof = ST_EOM_ERROR;
-      }
-    }
-    if (STps->eof == ST_EOM_OK)
-      return (-ENOSPC);
-    else if (STps->eof == ST_EOM_ERROR)
-      return (-EIO);
-
-    /* Check the buffer readability in cases where copy_user might catch
-       the problems after some tape movement. */
-    if (STp->block_size != 0 &&
-	(copy_from_user(&i, buf, 1) != 0 ||
-	 copy_from_user(&i, buf + count - 1, 1) != 0))
-	return (-EFAULT);
-
-    if (!STm->do_buffer_writes) {
-#if 0
-      if (STp->block_size != 0 && (count % STp->block_size) != 0)
-	return (-EIO);   /* Write must be integral number of blocks */
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev);
 #endif
-      write_threshold = 1;
-    }
-    else
-      write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
-    if (!STm->do_async_writes)
-      write_threshold--;
-
-    total = count;
-
-    memset(cmd, 0, 10);
-    cmd[0] = WRITE_6;
-    cmd[1] = (STp->block_size != 0);
-
-    STps->rw = ST_WRITING;
-
-    b_point = buf;
-    while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
-	   (STp->block_size != 0 &&
-	    (STp->buffer)->buffer_bytes + count > write_threshold))
-    {
-      doing_write = 1;
-      if (STp->block_size == 0)
-	do_count = count;
-      else {
-	do_count = (STp->buffer)->buffer_blocks * STp->block_size -
-	  (STp->buffer)->buffer_bytes;
-	if (do_count > count)
-	  do_count = count;
-      }
-
-      i = append_to_buffer(b_point, STp->buffer, do_count);
-      if (i) {
-	  if (SCpnt != NULL) {
-	      scsi_release_command(SCpnt);
-	      SCpnt = NULL;
-	  }
-	  return i;
-      }
-
-      if (STp->block_size == 0)
-	blks = transfer = do_count;
-      else {
-	blks = (STp->buffer)->buffer_bytes /
-	  STp->block_size;
-	transfer = blks * STp->block_size;
-      }
-      cmd[2] = blks >> 16;
-      cmd[3] = blks >> 8;
-      cmd[4] = blks;
-
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout,
-			 MAX_WRITE_RETRIES, TRUE);
-      if (!SCpnt)
-	return (-EBUSY);
+		STp->block_size = ST_DEFAULT_BLOCK;	/* Educated guess (?) */
+		(STp->buffer)->last_result_fatal = 0;	/* Prevent error propagation */
+		STp->drv_write_prot = 0;
+	} else {
 
-      if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
-	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Error on write:\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
+			       dev,
+			       (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
+			       (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]);
 #endif
-	if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-	    (SCpnt->sense_buffer[2] & 0x40)) {
-	  if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0)
-	    transfer = (SCpnt->sense_buffer[3] << 24) |
-	      (SCpnt->sense_buffer[4] << 16) |
-		(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
-	  else if (STp->block_size == 0 &&
-		   (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
-	    transfer = do_count;
-	  else
-	    transfer = 0;
-	  if (STp->block_size != 0)
-	    transfer *= STp->block_size;
-	  if (transfer <= do_count) {
-	    filp->f_pos += do_count - transfer;
-	    count -= do_count - transfer;
-	    if (STps->drv_block >= 0) {
-	      if (STp->block_size == 0 && transfer < do_count)
-		STps->drv_block++;
-	      else if (STp->block_size != 0)
-		STps->drv_block += (do_count - transfer) / STp->block_size;
-	    }
-	    STps->eof = ST_EOM_OK;
-	    retval = (-ENOSPC); /* EOM within current request */
-#if DEBUG
-	    if (debugging)
-	      printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n",
-		     dev, transfer);
-#endif
-	  }
-	  else {
-	    STps->eof = ST_EOM_ERROR;
-	    STps->drv_block = (-1);    /* Too cautious? */
-	    retval = (-EIO); /* EOM for old data */
+
+		if ((STp->buffer)->b_data[3] >= 8) {
+			STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
+			STp->density = (STp->buffer)->b_data[4];
+			STp->block_size = (STp->buffer)->b_data[9] * 65536 +
+			    (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
 #if DEBUG
-	    if (debugging)
-	      printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev);
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n",
+				       dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
+				       (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
+				       STp->drv_buffer);
 #endif
-	  }
-	}
-	else {
-	  STps->drv_block = (-1);    /* Too cautious? */
-	  retval = (-EIO);
+		}
+		if (STp->block_size > (STp->buffer)->buffer_size &&
+		    !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
+			printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
+			       STp->block_size);
+			scsi_release_command(SCpnt);
+			(STp->buffer)->in_use = 0;
+			STp->buffer = NULL;
+			if (scsi_tapes[dev].device->host->hostt->module)
+				__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+			if (st_template.module)
+				__MOD_DEC_USE_COUNT(st_template.module);
+			return (-EIO);
+		}
+		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
 	}
-
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
-	(STp->buffer)->buffer_bytes = 0;
-	STp->dirty = 0;
-	if (count < total)
-	  return total - count;
-	else
-	  return retval;
-      }
-      filp->f_pos += do_count;
-      b_point += do_count;
-      count -= do_count;
-      if (STps->drv_block >= 0) {
-	if (STp->block_size == 0)
-	  STps->drv_block++;
-	else
-	  STps->drv_block += blks;
-      }
-      (STp->buffer)->buffer_bytes = 0;
-      STp->dirty = 0;
-    }
-    if (count != 0) {
-      STp->dirty = 1;
-      i = append_to_buffer(b_point, STp->buffer, count);
-      if (i) {
-	  if (SCpnt != NULL) {
-	      scsi_release_command(SCpnt);
-	      SCpnt = NULL;
-	  }
-	  return i;
-      }
-      filp->f_pos += count;
-      count = 0;
-    }
-
-    if (doing_write && (STp->buffer)->last_result_fatal != 0) {
-      scsi_release_command(SCpnt);
-      SCpnt = NULL;
-      return (STp->buffer)->last_result_fatal;
-    }
-
-    if (STm->do_async_writes &&
-	(((STp->buffer)->buffer_bytes >= STp->write_threshold &&
-	  (STp->buffer)->buffer_bytes >= STp->block_size) ||
-	 STp->block_size == 0) ) {
-      /* Schedule an asynchronous write */
-      if (STp->block_size == 0)
-	(STp->buffer)->writing = (STp->buffer)->buffer_bytes;
-      else
-	(STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
-	  STp->block_size) * STp->block_size;
-      STp->dirty = !((STp->buffer)->writing ==
-		     (STp->buffer)->buffer_bytes);
-
-      if (STp->block_size == 0)
-	blks = (STp->buffer)->writing;
-      else
-	blks = (STp->buffer)->writing / STp->block_size;
-      cmd[2] = blks >> 16;
-      cmd[3] = blks >> 8;
-      cmd[4] = blks;
-#if DEBUG
-      STp->write_pending = 1;
-#endif
-
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
-			 MAX_WRITE_RETRIES, FALSE);
-      if (SCpnt == NULL)
-	  return (-EIO);
-    }
-    else if (SCpnt != NULL) {
 	scsi_release_command(SCpnt);
 	SCpnt = NULL;
-    }
-    STps->at_sm &= (total == 0);
-    if (total > 0)
-	STps->eof = ST_NOEOF;
 
-    return( total);
-}
-
-/* Read data from the tape. Returns zero in the normal case, one if the
-   eof status has changed, and the negative error code in case of a
-   fatal error. Otherwise updates the buffer and the eof state. */
-static long
-read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt)
-{
-    int transfer, blks, bytes;
-    static unsigned char cmd[10];
-    Scsi_Cmnd *SCpnt;
-    Scsi_Tape *STp;
-    ST_mode * STm;
-    ST_partstat * STps;
-    int dev = TAPE_NR(inode->i_rdev);
-    int retval = 0;
-
-    if (count == 0)
-      return 0;
-
-    STp = &(scsi_tapes[dev]);
-    STm = &(STp->modes[STp->current_mode]);
-    STps = &(STp->ps[STp->partition]);
-    if (STps->eof == ST_FM_HIT)
-	return 1;
+	if (STp->block_size > 0)
+		(STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size;
+	else
+		(STp->buffer)->buffer_blocks = 1;
+	(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
 
-    memset(cmd, 0, 10);
-    cmd[0] = READ_6;
-    cmd[1] = (STp->block_size != 0);
-    if (STp->block_size == 0)
-	blks = bytes = count;
-    else {
-	if (STm->do_read_ahead) {
-	    blks = (STp->buffer)->buffer_blocks;
-	    bytes = blks * STp->block_size;
-	}
-	else {
-	    bytes = count;
-	    if (bytes > (STp->buffer)->buffer_size)
-		bytes = (STp->buffer)->buffer_size;
-	    blks = bytes / STp->block_size;
-	    bytes = blks * STp->block_size;
-	}
-    }
-    cmd[2] = blks >> 16;
-    cmd[3] = blks >> 8;
-    cmd[4] = blks;
-
-    SCpnt = *aSCpnt;
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE);
-    *aSCpnt = SCpnt;
-    if (!SCpnt)
-	return (-EBUSY);
-
-    (STp->buffer)->read_pointer = 0;
-    STps->at_sm = 0;
-
-    /* Something to check */
-    if ((STp->buffer)->last_result_fatal) {
-	retval = 1;
 #if DEBUG
 	if (debugging)
-	    printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
-		   dev,
-		   SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
-		   SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
-		   SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
-		   SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]);
-#endif
-	if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */
-
-	    if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
-		SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */
-
-	    if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */
-		/* Compute the residual count */
-		if ((SCpnt->sense_buffer[0] & 0x80) != 0)
-		    transfer = (SCpnt->sense_buffer[3] << 24) |
-			(SCpnt->sense_buffer[4] << 16) |
-			(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
-		else
-		    transfer = 0;
-		if (STp->block_size == 0 &&
-		    (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
-		    transfer = bytes;
-
-		if (SCpnt->sense_buffer[2] & 0x20) { /* ILI */
-		    if (STp->block_size == 0) {
-			if (transfer <= 0)
-			    transfer = 0;
-			(STp->buffer)->buffer_bytes = bytes - transfer;
-		    }
-		    else {
-		        scsi_release_command(SCpnt);
-			SCpnt = *aSCpnt = NULL;
-			if (transfer == blks) {  /* We did not get anything, error */
-			    printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
-			    if (STps->drv_block >= 0)
-				STps->drv_block += blks - transfer + 1;
-			    st_int_ioctl(inode, MTBSR, 1);
-			    return (-EIO);
-			}
-			/* We have some data, deliver it */
-			(STp->buffer)->buffer_bytes = (blks - transfer) *
-			    STp->block_size;
-#if DEBUG
-			if (debugging)
-			    printk(ST_DEB_MSG
-				   "st%d: ILI but enough data received %ld %d.\n",
-				   dev, count, (STp->buffer)->buffer_bytes);
-#endif
-			if (STps->drv_block >= 0)
-			    STps->drv_block += 1;
-			if (st_int_ioctl(inode, MTBSR, 1))
-			    return (-EIO);
-		    }
-		}
-		else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */
-		    if (STps->eof != ST_FM_HIT)
-			STps->eof = ST_FM_HIT;
-		    else
-			STps->eof = ST_EOD_2;
-		    if (STp->block_size == 0)
-			(STp->buffer)->buffer_bytes = 0;
-		    else
-			(STp->buffer)->buffer_bytes =
-			    bytes - transfer * STp->block_size;
-#if DEBUG
-		    if (debugging)
-			printk(ST_DEB_MSG
-			 "st%d: EOF detected (%d bytes read).\n",
-			       dev, (STp->buffer)->buffer_bytes);
+		printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
+		       STp->block_size, (STp->buffer)->buffer_size,
+		       (STp->buffer)->buffer_blocks);
 #endif
-		}
-		else if (SCpnt->sense_buffer[2] & 0x40) {
-		    if (STps->eof == ST_FM)
-			STps->eof = ST_EOD_1;
-		    else
-			STps->eof = ST_EOM_OK;
-		    if (STp->block_size == 0)
-			(STp->buffer)->buffer_bytes = bytes - transfer;
-		    else
-			(STp->buffer)->buffer_bytes =
-			    bytes - transfer * STp->block_size;
+
+	if (STp->drv_write_prot) {
+		STp->write_prot = 1;
 #if DEBUG
-		    if (debugging)
-			printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n",
-			       dev, (STp->buffer)->buffer_bytes);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Write protected\n", dev);
 #endif
+		if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
+			(STp->buffer)->in_use = 0;
+			STp->buffer = NULL;
+			if (scsi_tapes[dev].device->host->hostt->module)
+				__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+			if (st_template.module)
+				__MOD_DEC_USE_COUNT(st_template.module);
+			return (-EROFS);
 		}
-	    } /* end of EOF, EOM, ILI test */
-	    else { /* nonzero sense key */
+	}
+	if (STp->can_partitions && STp->nbr_partitions < 1) {
+		/* This code is reached when the device is opened for the first time
+		   after the driver has been initialized with tape in the drive and the
+		   partition support has been enabled. */
 #if DEBUG
 		if (debugging)
-		    printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev);
-#endif
-		STps->drv_block = (-1);
-		if (STps->eof == ST_FM &&
-		    (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
-#if DEBUG
-		    if (debugging)
-			printk(ST_DEB_MSG
-			       "st%d: Zero returned for first BLANK CHECK after EOF.\n",
-			       dev);
+			printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev);
 #endif
-		    STps->eof = ST_EOD_2;  /* First BLANK_CHECK after FM */
+		if ((STp->partition = find_partition(inode)) < 0) {
+			(STp->buffer)->in_use = 0;
+			STp->buffer = NULL;
+			if (scsi_tapes[dev].device->host->hostt->module)
+				__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+			if (st_template.module)
+				__MOD_DEC_USE_COUNT(st_template.module);
+			return STp->partition;
 		}
-		else /* Some other extended sense code */
-		    retval = (-EIO);
-	    }
-	} /* End of extended sense test */
-	else {  /* Non-extended sense */
-	    retval = (STp->buffer)->last_result_fatal;
+		STp->new_partition = STp->partition;
+		STp->nbr_partitions = 1;	/* This guess will be updated when necessary */
 	}
+	if (new_session) {	/* Change the drive parameters for the new mode */
+		STp->density_changed = STp->blksize_changed = FALSE;
+		STp->compression_changed = FALSE;
+		if (!(STm->defaults_for_writes) &&
+		    (i = set_mode_densblk(inode, STp, STm)) < 0) {
+			(STp->buffer)->in_use = 0;
+			STp->buffer = NULL;
+			if (scsi_tapes[dev].device->host->hostt->module)
+				__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+			if (st_template.module)
+				__MOD_DEC_USE_COUNT(st_template.module);
+			return i;
+		}
+		if (STp->default_drvbuffer != 0xff) {
+			if (st_int_ioctl(inode, MTSETDRVBUFFER, STp->default_drvbuffer))
+				printk(KERN_WARNING "st%d: Can't set default drive buffering to %d.\n",
+				       dev, STp->default_drvbuffer);
+		}
+	}
+	STp->in_use = 1;
 
-    } /* End of error handling */
-    else /* Read successful */
-	(STp->buffer)->buffer_bytes = bytes;
-
-    if (STps->drv_block >= 0) {
-	if (STp->block_size == 0)
-	    STps->drv_block++;
-	else
-	    STps->drv_block += (STp->buffer)->buffer_bytes / STp->block_size;
-    }
-
-    return retval;
+	return 0;
 }
-
 
-/* Read command */
-static ssize_t
-st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+
+/* Flush the tape buffer before close */
+static int scsi_tape_flush(struct file *filp)
 {
-    struct inode * inode = filp->f_dentry->d_inode;
-    ssize_t total;
-    ssize_t i, transfer;
-    int special;
-    Scsi_Cmnd * SCpnt = NULL;
-    Scsi_Tape * STp;
-    ST_mode * STm;
-    ST_partstat * STps;
-    int dev = TAPE_NR(inode->i_rdev);
-
-    STp = &(scsi_tapes[dev]);
-
-    /*
-     * If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.
-     */
-    if( !scsi_block_when_processing_errors(STp->device) ) {
-        return -ENXIO;
-    }
-    
-    if (ppos != &filp->f_pos) {
-      /* "A request was outside the capabilities of the device." */
-      return -ENXIO;
-    }
-
-    if (STp->ready != ST_READY) {
-      if (STp->ready == ST_NO_TAPE)
-	return (-ENOMEDIUM);
-      else
-        return (-EIO);
-    }
-    STm = &(STp->modes[STp->current_mode]);
-    if (!STm->defined)
-      return (-ENXIO);
-#if DEBUG
-    if (!STp->in_use) {
-      printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
-      return (-EIO);
-    }
-#endif
-
-    if (STp->can_partitions &&
-	(total = update_partition(inode)) < 0)
-      return total;
-
-    if (STp->block_size == 0 &&
-	count > (STp->buffer)->buffer_size &&
-	!enlarge_buffer(STp->buffer, count, STp->restr_dma))
-      return (-EOVERFLOW);
-
-    if (!(STm->do_read_ahead) && STp->block_size != 0 &&
-	(count % STp->block_size) != 0)
-      return (-EIO);	/* Read must be integral number of blocks */
-
-    if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
-	!st_int_ioctl(inode, MTLOCK, 0))
-      STp->door_locked = ST_LOCKED_AUTO;
-
-    STps = &(STp->ps[STp->partition]);
-    if (STps->rw == ST_WRITING) {
-      transfer = flush_buffer(inode, filp, 0);
-      if (transfer)
-	return transfer;
-      STps->rw = ST_READING;
-    }
-
-#if DEBUG
-    if (debugging && STps->eof != ST_NOEOF)
-      printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev,
-	     STps->eof, (STp->buffer)->buffer_bytes);
-#endif
-    if ((STp->buffer)->buffer_bytes == 0 &&
-	STps->eof >= ST_EOD_1) {
-	if (STps->eof < ST_EOD) {
-	    STps->eof += 1;
-	    return 0;
-	}
-	return (-EIO);  /* EOM or Blank Check */
-    }
-
-    /* Check the buffer writability before any tape movement. Don't alter
-       buffer data. */
-    if (copy_from_user(&i, buf, 1) != 0 ||
-	copy_to_user(buf, &i, 1) != 0 ||
-	copy_from_user(&i, buf + count - 1, 1) != 0 ||
-	copy_to_user(buf + count - 1, &i, 1) != 0)
-	return (-EFAULT);
-
-    STps->rw = ST_READING;
-
-
-    /* Loop until enough data in buffer or a special condition found */
-    for (total = 0, special = 0; total < count && !special; ) {
-
-      /* Get new data if the buffer is empty */
-      if ((STp->buffer)->buffer_bytes == 0) {
-	  special = read_tape(inode, count - total, &SCpnt);
-	  if (special < 0) { /* No need to continue read */
-	      if (SCpnt != NULL) {
-		  scsi_release_command(SCpnt);
-	      }
-	      return special;
-	  }
-      }
+	int result = 0, result2;
+	static unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	ST_partstat *STps;
+
+	struct inode *inode = filp->f_dentry->d_inode;
+	kdev_t devt = inode->i_rdev;
+	int dev;
+
+	if (file_count(filp) > 1)
+		return 0;
+
+	dev = TAPE_NR(devt);
+	STp = &(scsi_tapes[dev]);
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
 
-      /* Move the data from driver buffer to user buffer */
-      if ((STp->buffer)->buffer_bytes > 0) {
+	if (STp->can_partitions &&
+	    (result = update_partition(inode)) < 0) {
 #if DEBUG
-	if (debugging && STps->eof != ST_NOEOF)
-	  printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev,
-		 STps->eof, (STp->buffer)->buffer_bytes, count - total);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev);
 #endif
-	transfer = (STp->buffer)->buffer_bytes < count - total ?
-	  (STp->buffer)->buffer_bytes : count - total;
-	i = from_buffer(STp->buffer, buf, transfer);
-	if (i) {
-	    if (SCpnt != NULL) {
-		scsi_release_command(SCpnt);
-		SCpnt = NULL;
-	    }
-	    return i;
+		goto out;
 	}
-	filp->f_pos += transfer;
-	buf += transfer;
-	total += transfer;
-      }
-
-      if (STp->block_size == 0)
-	  break;  /* Read only one variable length block */
+	if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
 
-    } /* for (total = 0, special = 0; total < count && !special; ) */
+		result = flush_write_buffer(STp);
 
-    if (SCpnt != NULL) {
-	scsi_release_command(SCpnt);
-	SCpnt = NULL;
-    }
+#if DEBUG
+		if (debugging) {
+			printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
+			       dev, (long) (filp->f_pos));
+			printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
+			       dev, STp->nbr_waits, STp->nbr_finished);
+		}
+#endif
 
-    /* Change the eof state if no data from tape or buffer */
-    if (total == 0) {
-	if (STps->eof == ST_FM_HIT) {
-	    STps->eof = ST_FM;
-	    STps->drv_block = 0;
-	    if (STps->drv_file >= 0)
-		STps->drv_file++;
-	}
-	else if (STps->eof == ST_EOD_1) {
-	    STps->eof = ST_EOD_2;
-	    STps->drv_block = 0;
-	    if (STps->drv_file >= 0)
-		STps->drv_file++;
-	}
-	else if (STps->eof == ST_EOD_2)
-	    STps->eof = ST_EOD;
-    }
-    else if (STps->eof == ST_FM)
-	STps->eof = ST_NOEOF;
+		if (result == 0 || result == (-ENOSPC)) {
 
-    return total;
+			memset(cmd, 0, 10);
+			cmd[0] = WRITE_FILEMARKS;
+			cmd[4] = 1 + STp->two_fm;
+
+			SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES,
+					   TRUE);
+			if (!SCpnt)
+				goto out;
+
+			if ((STp->buffer)->last_result_fatal != 0 &&
+			    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+			     (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
+			     ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
+			(SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
+			 SCpnt->sense_buffer[5] |
+			 SCpnt->sense_buffer[6]) == 0))) {
+				/* Filter out successful write at EOM */
+				scsi_release_command(SCpnt);
+				SCpnt = NULL;
+				printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
+				if (result == 0)
+					result = (-EIO);
+			} else {
+				scsi_release_command(SCpnt);
+				SCpnt = NULL;
+				if (STps->drv_file >= 0)
+					STps->drv_file++;
+				STps->drv_block = 0;
+				if (STp->two_fm)
+					cross_eof(STp, FALSE);
+				STps->eof = ST_FM;
+			}
+		}
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
+			       dev, cmd[4]);
+#endif
+	} else if (!STp->rew_at_close) {
+		STps = &(STp->ps[STp->partition]);
+		if (!STm->sysv || STps->rw != ST_READING) {
+			if (STp->can_bsr)
+				result = flush_buffer(inode, filp, 0);
+			else if (STps->eof == ST_FM_HIT) {
+				result = cross_eof(STp, FALSE);
+				if (result) {
+					if (STps->drv_file >= 0)
+						STps->drv_file++;
+					STps->drv_block = 0;
+					STps->eof = ST_FM;
+				} else
+					STps->eof = ST_NOEOF;
+			}
+		} else if ((STps->eof == ST_NOEOF &&
+			    !(result = cross_eof(STp, TRUE))) ||
+			   STps->eof == ST_FM_HIT) {
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+			STps->drv_block = 0;
+			STps->eof = ST_FM;
+		}
+	}
+      out:
+	if (STp->rew_at_close) {
+		result2 = st_int_ioctl(inode, MTREW, 1);
+		if (result == 0)
+			result = result2;
+	}
+	return result;
 }
 
 
-
-/* Set the driver options */
-	static void
-st_log_options(Scsi_Tape *STp, ST_mode *STm, int dev)
+/* Close the device and release it */
+static int scsi_tape_close(struct inode *inode, struct file *filp)
 {
-  printk(KERN_INFO
-"st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
-	 dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
-	 STm->do_read_ahead);
-  printk(KERN_INFO
-"st%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
-	 dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
-  printk(KERN_INFO
-"st%d:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
-	 dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
-	 STp->scsi2_logical);
-  printk(KERN_INFO
-"st%d:    sysv: %d\n", dev, STm->sysv);
-#if DEBUG
-  printk(KERN_INFO
-	 "st%d:    debugging: %d\n",
-	 dev, debugging);
-#endif
-}
-
-
-	static int
-st_set_options(struct inode * inode, long options)
-{
-  int value;
-  long code;
-  Scsi_Tape *STp;
-  ST_mode *STm;
-  int dev = TAPE_NR(inode->i_rdev);
-
-  STp = &(scsi_tapes[dev]);
-  STm = &(STp->modes[STp->current_mode]);
-  if (!STm->defined) {
-    memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
-    modes_defined = TRUE;
-#if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n",
-	     dev, STp->current_mode);
-#endif
-  }
-
-  code = options & MT_ST_OPTIONS;
-  if (code == MT_ST_BOOLEANS) {
-    STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
-    STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
-    STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
-    STm->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
-    STp->two_fm		  = (options & MT_ST_TWO_FM) != 0;
-    STp->fast_mteom	  = (options & MT_ST_FAST_MTEOM) != 0;
-    STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
-    STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
-    STp->omit_blklims	  = (options & MT_ST_NO_BLKLIMS) != 0;
-    if ((STp->device)->scsi_level >= SCSI_2)
-      STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
-    STp->scsi2_logical    = (options & MT_ST_SCSI2LOGICAL) != 0;
-    STm->sysv		  = (options & MT_ST_SYSV) != 0;
-#if DEBUG
-    debugging = (options & MT_ST_DEBUGGING) != 0;
-#endif
-    st_log_options(STp, STm, dev);
-  }
-  else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
-    value = (code == MT_ST_SETBOOLEANS);
-    if ((options & MT_ST_BUFFER_WRITES) != 0)
-      STm->do_buffer_writes = value;
-    if ((options & MT_ST_ASYNC_WRITES) != 0)
-      STm->do_async_writes = value;
-    if ((options & MT_ST_DEF_WRITES) != 0)
-      STm->defaults_for_writes = value;
-    if ((options & MT_ST_READ_AHEAD) != 0)
-      STm->do_read_ahead = value;
-    if ((options & MT_ST_TWO_FM) != 0)
-      STp->two_fm = value;
-    if ((options & MT_ST_FAST_MTEOM) != 0)
-      STp->fast_mteom = value;
-    if ((options & MT_ST_AUTO_LOCK) != 0)
-      STp->do_auto_lock = value;
-    if ((options & MT_ST_CAN_BSR) != 0)
-      STp->can_bsr = value;
-    if ((options & MT_ST_NO_BLKLIMS) != 0)
-      STp->omit_blklims = value;
-    if ((STp->device)->scsi_level >= SCSI_2 &&
-	(options & MT_ST_CAN_PARTITIONS) != 0)
-      STp->can_partitions = value;
-    if ((options & MT_ST_SCSI2LOGICAL) != 0)
-      STp->scsi2_logical = value;
-    if ((options & MT_ST_SYSV) != 0)
-      STm->sysv = value;
-#if DEBUG
-    if ((options & MT_ST_DEBUGGING) != 0)
-      debugging = value;
-#endif
-    st_log_options(STp, STm, dev);
-  }
-  else if (code == MT_ST_WRITE_THRESHOLD) {
-    value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
-    if (value < 1 || value > st_buffer_size) {
-      printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n",
-	     dev, value);
-      return (-EIO);
-    }
-    STp->write_threshold = value;
-    printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n",
-	   dev, value);
-  }
-  else if (code == MT_ST_DEF_BLKSIZE) {
-    value = (options & ~MT_ST_OPTIONS);
-    if (value == ~MT_ST_OPTIONS) {
-      STm->default_blksize = (-1);
-      printk(KERN_INFO "st%d: Default block size disabled.\n", dev);
-    }
-    else {
-      STm->default_blksize = value;
-      printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
-	     dev, STm->default_blksize);
-    }
-  }
-  else if (code == MT_ST_TIMEOUTS) {
-    value = (options & ~MT_ST_OPTIONS);
-    if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
-      STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
-      printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev,
-	     (value & ~MT_ST_SET_LONG_TIMEOUT));
-    }
-    else {
-      STp->timeout = value * HZ;
-      printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev,
-	     value);
-    }
-  }
-  else if (code == MT_ST_DEF_OPTIONS) {
-    code = (options & ~MT_ST_CLEAR_DEFAULT);
-    value = (options & MT_ST_CLEAR_DEFAULT);
-    if (code == MT_ST_DEF_DENSITY) {
-      if (value == MT_ST_CLEAR_DEFAULT) {
-	STm->default_density = (-1);
-	printk(KERN_INFO "st%d: Density default disabled.\n", dev);
-      }
-      else {
-	STm->default_density = value & 0xff;
-	printk(KERN_INFO "st%d: Density default set to %x\n",
-	       dev, STm->default_density);
-      }
-    }
-    else if (code == MT_ST_DEF_DRVBUFFER) {
-      if (value == MT_ST_CLEAR_DEFAULT) {
-	STp->default_drvbuffer = 0xff;
-	printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev);
-      }
-      else {
-	STp->default_drvbuffer = value & 7;
-	printk(KERN_INFO "st%d: Drive buffer default set to %x\n",
-	       dev, STp->default_drvbuffer);
-      }
-    }
-    else if (code == MT_ST_DEF_COMPRESSION) {
-      if (value == MT_ST_CLEAR_DEFAULT) {
-	STm->default_compression = ST_DONT_TOUCH;
-	printk(KERN_INFO "st%d: Compression default disabled.\n", dev);
-      }
-      else {
-	STm->default_compression = (value & 1 ? ST_YES : ST_NO);
-	printk(KERN_INFO "st%d: Compression default set to %x\n",
-	       dev, (value & 1));
-      }
-    }
-  }
-  else
-    return (-EIO);
+	int result = 0;
+	Scsi_Tape *STp;
 
-  return 0;
-}
+	kdev_t devt = inode->i_rdev;
+	int dev;
 
-
-#define COMPRESSION_PAGE        0x0f
-#define COMPRESSION_PAGE_LENGTH 16
+	dev = TAPE_NR(devt);
+	STp = &(scsi_tapes[dev]);
 
-#define MODE_HEADER_LENGTH  4
+	if (STp->door_locked == ST_LOCKED_AUTO)
+		st_int_ioctl(inode, MTUNLOCK, 0);
 
-#define DCE_MASK  0x80
-#define DCC_MASK  0x40
-#define RED_MASK  0x60
+	if (STp->buffer != NULL) {
+		normalize_buffer(STp->buffer);
+		(STp->buffer)->in_use = 0;
+	}
+	STp->in_use = 0;
+	if (scsi_tapes[dev].device->host->hostt->module)
+		__MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if (st_template.module)
+		__MOD_DEC_USE_COUNT(st_template.module);
 
+	return result;
+}
+
 
-/* Control the compression with mode page 15. Algorithm not changed if zero. */
-	static int
-st_compression(Scsi_Tape * STp, int state)
+/* Write command */
+static ssize_t
+ st_write(struct file *filp, const char *buf, size_t count, loff_t * ppos)
 {
-  int dev;
-  unsigned char cmd[10];
-  Scsi_Cmnd * SCpnt = NULL;
-
-  if (STp->ready != ST_READY)
-    return (-EIO);
-
-  /* Read the current page contents */
-  memset(cmd, 0, 10);
-  cmd[0] = MODE_SENSE;
-  cmd[1] = 8;
-  cmd[2] = COMPRESSION_PAGE;
-  cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
-
-  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
-  if (SCpnt == NULL)
-    return (-EBUSY);
-  dev = TAPE_NR(SCpnt->request.rq_dev);
+	struct inode *inode = filp->f_dentry->d_inode;
+	ssize_t total;
+	ssize_t i, do_count, blks, retval, transfer;
+	int write_threshold;
+	int doing_write = 0;
+	static unsigned char cmd[10];
+	const char *b_point;
+	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	STp = &(scsi_tapes[dev]);
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(STp->device)) {
+		return -ENXIO;
+	}
+	if (ppos != &filp->f_pos) {
+		/* "A request was outside the capabilities of the device." */
+		return -ENXIO;
+	}
+	if (STp->ready != ST_READY) {
+		if (STp->ready == ST_NO_TAPE)
+			return (-ENOMEDIUM);
+		else
+			return (-EIO);
+	}
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined)
+		return (-ENXIO);
+	if (count == 0)
+		return 0;
+
+	/*
+	 * If there was a bus reset, block further access
+	 * to this device.
+	 */
+	if (STp->device->was_reset)
+		return (-EIO);
+
+#if DEBUG
+	if (!STp->in_use) {
+		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
+		return (-EIO);
+	}
+#endif
+
+	/* Write must be integral number of blocks */
+	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+		printk(KERN_WARNING "st%d: Write not multiple of tape block size.\n",
+		       dev);
+		return (-EIO);
+	}
+	if (STp->can_partitions &&
+	    (retval = update_partition(inode)) < 0)
+		return retval;
+	STps = &(STp->ps[STp->partition]);
 
-  if ((STp->buffer)->last_result_fatal != 0) {
+	if (STp->write_prot)
+		return (-EACCES);
+
+	if (STp->block_size == 0 &&
+	    count > (STp->buffer)->buffer_size &&
+	    !enlarge_buffer(STp->buffer, count, STp->restr_dma))
+		return (-EOVERFLOW);
+
+	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
+	    !st_int_ioctl(inode, MTLOCK, 0))
+		STp->door_locked = ST_LOCKED_AUTO;
+
+	if (STps->rw == ST_READING) {
+		retval = flush_buffer(inode, filp, 0);
+		if (retval)
+			return retval;
+		STps->rw = ST_WRITING;
+	} else if (STps->rw != ST_WRITING &&
+		   STps->drv_file == 0 && STps->drv_block == 0) {
+		if ((retval = set_mode_densblk(inode, STp, STm)) < 0)
+			return retval;
+		if (STm->default_compression != ST_DONT_TOUCH &&
+		    !(STp->compression_changed)) {
+			if (st_compression(STp, (STm->default_compression == ST_YES))) {
+				printk(KERN_WARNING "st%d: Can't set default compression.\n",
+				       dev);
+				if (modes_defined)
+					return (-EINVAL);
+			}
+		}
+	}
+	if ((STp->buffer)->writing) {
+		write_behind_check(STp);
+		if ((STp->buffer)->last_result_fatal) {
 #if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev,
+				       (STp->buffer)->last_result);
 #endif
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-    return (-EIO);
-  }
+			if ((STp->buffer)->last_result == INT_MAX)
+				STps->eof = ST_EOM_OK;
+			else
+				STps->eof = ST_EOM_ERROR;
+		}
+	}
+	if (STps->eof == ST_EOM_OK)
+		return (-ENOSPC);
+	else if (STps->eof == ST_EOM_ERROR)
+		return (-EIO);
+
+	/* Check the buffer readability in cases where copy_user might catch
+	   the problems after some tape movement. */
+	if (STp->block_size != 0 &&
+	    (copy_from_user(&i, buf, 1) != 0 ||
+	     copy_from_user(&i, buf + count - 1, 1) != 0))
+		return (-EFAULT);
+
+	if (!STm->do_buffer_writes) {
+#if 0
+		if (STp->block_size != 0 && (count % STp->block_size) != 0)
+			return (-EIO);	/* Write must be integral number of blocks */
+#endif
+		write_threshold = 1;
+	} else
+		write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
+	if (!STm->do_async_writes)
+		write_threshold--;
+
+	total = count;
+
+	memset(cmd, 0, 10);
+	cmd[0] = WRITE_6;
+	cmd[1] = (STp->block_size != 0);
+
+	STps->rw = ST_WRITING;
+
+	b_point = buf;
+	while ((STp->block_size == 0 && !STm->do_async_writes && count > 0) ||
+	       (STp->block_size != 0 &&
+		(STp->buffer)->buffer_bytes + count > write_threshold)) {
+		doing_write = 1;
+		if (STp->block_size == 0)
+			do_count = count;
+		else {
+			do_count = (STp->buffer)->buffer_blocks * STp->block_size -
+			    (STp->buffer)->buffer_bytes;
+			if (do_count > count)
+				do_count = count;
+		}
+
+		i = append_to_buffer(b_point, STp->buffer, do_count);
+		if (i) {
+			if (SCpnt != NULL) {
+				scsi_release_command(SCpnt);
+				SCpnt = NULL;
+			}
+			return i;
+		}
+		if (STp->block_size == 0)
+			blks = transfer = do_count;
+		else {
+			blks = (STp->buffer)->buffer_bytes /
+			    STp->block_size;
+			transfer = blks * STp->block_size;
+		}
+		cmd[2] = blks >> 16;
+		cmd[3] = blks >> 8;
+		cmd[4] = blks;
+
+		SCpnt = st_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout,
+				   MAX_WRITE_RETRIES, TRUE);
+		if (!SCpnt)
+			return (-EBUSY);
+
+		if ((STp->buffer)->last_result_fatal != 0) {
 #if DEBUG
-  if (debugging)
-    printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
-	   ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0));
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Error on write:\n", dev);
+#endif
+			if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+			    (SCpnt->sense_buffer[2] & 0x40)) {
+				if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0)
+					transfer = (SCpnt->sense_buffer[3] << 24) |
+					    (SCpnt->sense_buffer[4] << 16) |
+					    (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+				else if (STp->block_size == 0 &&
+					 (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
+					transfer = do_count;
+				else
+					transfer = 0;
+				if (STp->block_size != 0)
+					transfer *= STp->block_size;
+				if (transfer <= do_count) {
+					filp->f_pos += do_count - transfer;
+					count -= do_count - transfer;
+					if (STps->drv_block >= 0) {
+						if (STp->block_size == 0 && transfer < do_count)
+							STps->drv_block++;
+						else if (STp->block_size != 0)
+							STps->drv_block += (do_count - transfer) / STp->block_size;
+					}
+					STps->eof = ST_EOM_OK;
+					retval = (-ENOSPC);	/* EOM within current request */
+#if DEBUG
+					if (debugging)
+						printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n",
+						       dev, transfer);
+#endif
+				} else {
+					STps->eof = ST_EOM_ERROR;
+					STps->drv_block = (-1);		/* Too cautious? */
+					retval = (-EIO);	/* EOM for old data */
+#if DEBUG
+					if (debugging)
+						printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev);
+#endif
+				}
+			} else {
+				STps->drv_block = (-1);		/* Too cautious? */
+				retval = (-EIO);
+			}
+
+			scsi_release_command(SCpnt);
+			SCpnt = NULL;
+			(STp->buffer)->buffer_bytes = 0;
+			STp->dirty = 0;
+			if (count < total)
+				return total - count;
+			else
+				return retval;
+		}
+		filp->f_pos += do_count;
+		b_point += do_count;
+		count -= do_count;
+		if (STps->drv_block >= 0) {
+			if (STp->block_size == 0)
+				STps->drv_block++;
+			else
+				STps->drv_block += blks;
+		}
+		(STp->buffer)->buffer_bytes = 0;
+		STp->dirty = 0;
+	}
+	if (count != 0) {
+		STp->dirty = 1;
+		i = append_to_buffer(b_point, STp->buffer, count);
+		if (i) {
+			if (SCpnt != NULL) {
+				scsi_release_command(SCpnt);
+				SCpnt = NULL;
+			}
+			return i;
+		}
+		filp->f_pos += count;
+		count = 0;
+	}
+	if (doing_write && (STp->buffer)->last_result_fatal != 0) {
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+		return (STp->buffer)->last_result_fatal;
+	}
+	if (STm->do_async_writes &&
+	    (((STp->buffer)->buffer_bytes >= STp->write_threshold &&
+	      (STp->buffer)->buffer_bytes >= STp->block_size) ||
+	     STp->block_size == 0)) {
+		/* Schedule an asynchronous write */
+		if (STp->block_size == 0)
+			(STp->buffer)->writing = (STp->buffer)->buffer_bytes;
+		else
+			(STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
+				      STp->block_size) * STp->block_size;
+		STp->dirty = !((STp->buffer)->writing ==
+			       (STp->buffer)->buffer_bytes);
+
+		if (STp->block_size == 0)
+			blks = (STp->buffer)->writing;
+		else
+			blks = (STp->buffer)->writing / STp->block_size;
+		cmd[2] = blks >> 16;
+		cmd[3] = blks >> 8;
+		cmd[4] = blks;
+#if DEBUG
+		STp->write_pending = 1;
 #endif
 
-  /* Check if compression can be changed */
-  if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
+		SCpnt = st_do_scsi(SCpnt, STp, cmd, (STp->buffer)->writing, STp->timeout,
+				   MAX_WRITE_RETRIES, FALSE);
+		if (SCpnt == NULL)
+			return (-EIO);
+	} else if (SCpnt != NULL) {
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+	}
+	STps->at_sm &= (total == 0);
+	if (total > 0)
+		STps->eof = ST_NOEOF;
+
+	return (total);
+}
+
+/* Read data from the tape. Returns zero in the normal case, one if the
+   eof status has changed, and the negative error code in case of a
+   fatal error. Otherwise updates the buffer and the eof state. */
+static long read_tape(struct inode *inode, long count, Scsi_Cmnd ** aSCpnt)
+{
+	int transfer, blks, bytes;
+	static unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+	int retval = 0;
+
+	if (count == 0)
+		return 0;
+
+	STp = &(scsi_tapes[dev]);
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
+	if (STps->eof == ST_FM_HIT)
+		return 1;
+
+	memset(cmd, 0, 10);
+	cmd[0] = READ_6;
+	cmd[1] = (STp->block_size != 0);
+	if (STp->block_size == 0)
+		blks = bytes = count;
+	else {
+		if (STm->do_read_ahead) {
+			blks = (STp->buffer)->buffer_blocks;
+			bytes = blks * STp->block_size;
+		} else {
+			bytes = count;
+			if (bytes > (STp->buffer)->buffer_size)
+				bytes = (STp->buffer)->buffer_size;
+			blks = bytes / STp->block_size;
+			bytes = blks * STp->block_size;
+		}
+	}
+	cmd[2] = blks >> 16;
+	cmd[3] = blks >> 8;
+	cmd[4] = blks;
+
+	SCpnt = *aSCpnt;
+	SCpnt = st_do_scsi(SCpnt, STp, cmd, bytes, STp->timeout, MAX_RETRIES, TRUE);
+	*aSCpnt = SCpnt;
+	if (!SCpnt)
+		return (-EBUSY);
+
+	(STp->buffer)->read_pointer = 0;
+	STps->at_sm = 0;
+
+	/* Something to check */
+	if ((STp->buffer)->last_result_fatal) {
+		retval = 1;
 #if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+			       dev,
+			  SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
+			  SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
+			  SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
+			 SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]);
+#endif
+		if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) {	/* extended sense */
+
+			if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+				SCpnt->sense_buffer[2] &= 0xcf;		/* No need for EOM in this case */
+
+			if ((SCpnt->sense_buffer[2] & 0xe0) != 0) {	/* EOF, EOM, or ILI */
+				/* Compute the residual count */
+				if ((SCpnt->sense_buffer[0] & 0x80) != 0)
+					transfer = (SCpnt->sense_buffer[3] << 24) |
+					    (SCpnt->sense_buffer[4] << 16) |
+					    (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+				else
+					transfer = 0;
+				if (STp->block_size == 0 &&
+				    (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR)
+					transfer = bytes;
+
+				if (SCpnt->sense_buffer[2] & 0x20) {	/* ILI */
+					if (STp->block_size == 0) {
+						if (transfer <= 0)
+							transfer = 0;
+						(STp->buffer)->buffer_bytes = bytes - transfer;
+					} else {
+						scsi_release_command(SCpnt);
+						SCpnt = *aSCpnt = NULL;
+						if (transfer == blks) {		/* We did not get anything, error */
+							printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
+							if (STps->drv_block >= 0)
+								STps->drv_block += blks - transfer + 1;
+							st_int_ioctl(inode, MTBSR, 1);
+							return (-EIO);
+						}
+						/* We have some data, deliver it */
+						(STp->buffer)->buffer_bytes = (blks - transfer) *
+						    STp->block_size;
+#if DEBUG
+						if (debugging)
+							printk(ST_DEB_MSG
+							       "st%d: ILI but enough data received %ld %d.\n",
+							       dev, count, (STp->buffer)->buffer_bytes);
+#endif
+						if (STps->drv_block >= 0)
+							STps->drv_block += 1;
+						if (st_int_ioctl(inode, MTBSR, 1))
+							return (-EIO);
+					}
+				} else if (SCpnt->sense_buffer[2] & 0x80) {	/* FM overrides EOM */
+					if (STps->eof != ST_FM_HIT)
+						STps->eof = ST_FM_HIT;
+					else
+						STps->eof = ST_EOD_2;
+					if (STp->block_size == 0)
+						(STp->buffer)->buffer_bytes = 0;
+					else
+						(STp->buffer)->buffer_bytes =
+						    bytes - transfer * STp->block_size;
+#if DEBUG
+					if (debugging)
+						printk(ST_DEB_MSG
+						       "st%d: EOF detected (%d bytes read).\n",
+						       dev, (STp->buffer)->buffer_bytes);
+#endif
+				} else if (SCpnt->sense_buffer[2] & 0x40) {
+					if (STps->eof == ST_FM)
+						STps->eof = ST_EOD_1;
+					else
+						STps->eof = ST_EOM_OK;
+					if (STp->block_size == 0)
+						(STp->buffer)->buffer_bytes = bytes - transfer;
+					else
+						(STp->buffer)->buffer_bytes =
+						    bytes - transfer * STp->block_size;
+#if DEBUG
+					if (debugging)
+						printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n",
+						       dev, (STp->buffer)->buffer_bytes);
 #endif
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-    return (-EIO);
-  }
+				}
+			}
+			/* end of EOF, EOM, ILI test */ 
+			else {	/* nonzero sense key */
+#if DEBUG
+				if (debugging)
+					printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev);
+#endif
+				STps->drv_block = (-1);
+				if (STps->eof == ST_FM &&
+				    (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
+#if DEBUG
+					if (debugging)
+						printk(ST_DEB_MSG
+						       "st%d: Zero returned for first BLANK CHECK after EOF.\n",
+						       dev);
+#endif
+					STps->eof = ST_EOD_2;	/* First BLANK_CHECK after FM */
+				} else	/* Some other extended sense code */
+					retval = (-EIO);
+			}
+		}
+		/* End of extended sense test */ 
+		else {		/* Non-extended sense */
+			retval = (STp->buffer)->last_result_fatal;
+		}
 
-  /* Do the change */
-  if (state)
-    (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK;
-  else
-    (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
+	}
+	/* End of error handling */ 
+	else			/* Read successful */
+		(STp->buffer)->buffer_bytes = bytes;
+
+	if (STps->drv_block >= 0) {
+		if (STp->block_size == 0)
+			STps->drv_block++;
+		else
+			STps->drv_block += (STp->buffer)->buffer_bytes / STp->block_size;
+	}
+	return retval;
+}
+
 
-  memset(cmd, 0, 10);
-  cmd[0] = MODE_SELECT;
-  cmd[1] = 0x10;
-  cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
+/* Read command */
+static ssize_t
+ st_read(struct file *filp, char *buf, size_t count, loff_t * ppos)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	ssize_t total;
+	ssize_t i, transfer;
+	int special;
+	Scsi_Cmnd *SCpnt = NULL;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	STp = &(scsi_tapes[dev]);
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(STp->device)) {
+		return -ENXIO;
+	}
+	if (ppos != &filp->f_pos) {
+		/* "A request was outside the capabilities of the device." */
+		return -ENXIO;
+	}
+	if (STp->ready != ST_READY) {
+		if (STp->ready == ST_NO_TAPE)
+			return (-ENOMEDIUM);
+		else
+			return (-EIO);
+	}
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined)
+		return (-ENXIO);
+#if DEBUG
+	if (!STp->in_use) {
+		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
+		return (-EIO);
+	}
+#endif
 
-  (STp->buffer)->b_data[0] = 0;  /* Reserved data length */
-  (STp->buffer)->b_data[1] = 0;  /* Reserved media type byte */
-  (STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
-  SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	if (STp->can_partitions &&
+	    (total = update_partition(inode)) < 0)
+		return total;
+
+	if (STp->block_size == 0 &&
+	    count > (STp->buffer)->buffer_size &&
+	    !enlarge_buffer(STp->buffer, count, STp->restr_dma))
+		return (-EOVERFLOW);
+
+	if (!(STm->do_read_ahead) && STp->block_size != 0 &&
+	    (count % STp->block_size) != 0)
+		return (-EIO);	/* Read must be integral number of blocks */
+
+	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
+	    !st_int_ioctl(inode, MTLOCK, 0))
+		STp->door_locked = ST_LOCKED_AUTO;
 
-  if ((STp->buffer)->last_result_fatal != 0) {
+	STps = &(STp->ps[STp->partition]);
+	if (STps->rw == ST_WRITING) {
+		transfer = flush_buffer(inode, filp, 0);
+		if (transfer)
+			return transfer;
+		STps->rw = ST_READING;
+	}
 #if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
+	if (debugging && STps->eof != ST_NOEOF)
+		printk(ST_DEB_MSG "st%d: EOF/EOM flag up (%d). Bytes %d\n", dev,
+		       STps->eof, (STp->buffer)->buffer_bytes);
+#endif
+	if ((STp->buffer)->buffer_bytes == 0 &&
+	    STps->eof >= ST_EOD_1) {
+		if (STps->eof < ST_EOD) {
+			STps->eof += 1;
+			return 0;
+		}
+		return (-EIO);	/* EOM or Blank Check */
+	}
+	/* Check the buffer writability before any tape movement. Don't alter
+	   buffer data. */
+	if (copy_from_user(&i, buf, 1) != 0 ||
+	    copy_to_user(buf, &i, 1) != 0 ||
+	    copy_from_user(&i, buf + count - 1, 1) != 0 ||
+	    copy_to_user(buf + count - 1, &i, 1) != 0)
+		return (-EFAULT);
+
+	STps->rw = ST_READING;
+
+
+	/* Loop until enough data in buffer or a special condition found */
+	for (total = 0, special = 0; total < count && !special;) {
+
+		/* Get new data if the buffer is empty */
+		if ((STp->buffer)->buffer_bytes == 0) {
+			special = read_tape(inode, count - total, &SCpnt);
+			if (special < 0) {	/* No need to continue read */
+				if (SCpnt != NULL) {
+					scsi_release_command(SCpnt);
+				}
+				return special;
+			}
+		}
+		/* Move the data from driver buffer to user buffer */
+		if ((STp->buffer)->buffer_bytes > 0) {
+#if DEBUG
+			if (debugging && STps->eof != ST_NOEOF)
+				printk(ST_DEB_MSG "st%d: EOF up (%d). Left %d, needed %d.\n", dev,
+				       STps->eof, (STp->buffer)->buffer_bytes, count - total);
+#endif
+			transfer = (STp->buffer)->buffer_bytes < count - total ?
+			    (STp->buffer)->buffer_bytes : count - total;
+			i = from_buffer(STp->buffer, buf, transfer);
+			if (i) {
+				if (SCpnt != NULL) {
+					scsi_release_command(SCpnt);
+					SCpnt = NULL;
+				}
+				return i;
+			}
+			filp->f_pos += transfer;
+			buf += transfer;
+			total += transfer;
+		}
+		if (STp->block_size == 0)
+			break;	/* Read only one variable length block */
+
+	}			/* for (total = 0, special = 0; total < count && !special; ) */
+
+	if (SCpnt != NULL) {
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+	}
+	/* Change the eof state if no data from tape or buffer */
+	if (total == 0) {
+		if (STps->eof == ST_FM_HIT) {
+			STps->eof = ST_FM;
+			STps->drv_block = 0;
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+		} else if (STps->eof == ST_EOD_1) {
+			STps->eof = ST_EOD_2;
+			STps->drv_block = 0;
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+		} else if (STps->eof == ST_EOD_2)
+			STps->eof = ST_EOD;
+	} else if (STps->eof == ST_FM)
+		STps->eof = ST_NOEOF;
+
+	return total;
+}
+
+
+
+/* Set the driver options */
+static void st_log_options(Scsi_Tape * STp, ST_mode * STm, int dev)
+{
+	printk(KERN_INFO
+	       "st%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+	       dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
+	       STm->do_read_ahead);
+	printk(KERN_INFO
+	       "st%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
+	       dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
+	printk(KERN_INFO
+	       "st%d:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
+	       dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
+	       STp->scsi2_logical);
+	printk(KERN_INFO
+	       "st%d:    sysv: %d\n", dev, STm->sysv);
+#if DEBUG
+	printk(KERN_INFO
+	       "st%d:    debugging: %d\n",
+	       dev, debugging);
 #endif
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-    return (-EIO);
-  }
+}
+
 
+static int st_set_options(struct inode *inode, long options)
+{
+	int value;
+	long code;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	STp = &(scsi_tapes[dev]);
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined) {
+		memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
+		modes_defined = TRUE;
 #if DEBUG
-  if (debugging)
-    printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
-	   dev, state);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Initialized mode %d definition from mode 0\n",
+			       dev, STp->current_mode);
 #endif
+	}
+	code = options & MT_ST_OPTIONS;
+	if (code == MT_ST_BOOLEANS) {
+		STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
+		STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
+		STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
+		STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
+		STp->two_fm = (options & MT_ST_TWO_FM) != 0;
+		STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
+		STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
+		STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
+		STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
+		if ((STp->device)->scsi_level >= SCSI_2)
+			STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
+		STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
+		STm->sysv = (options & MT_ST_SYSV) != 0;
+#if DEBUG
+		debugging = (options & MT_ST_DEBUGGING) != 0;
+#endif
+		st_log_options(STp, STm, dev);
+	} else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
+		value = (code == MT_ST_SETBOOLEANS);
+		if ((options & MT_ST_BUFFER_WRITES) != 0)
+			STm->do_buffer_writes = value;
+		if ((options & MT_ST_ASYNC_WRITES) != 0)
+			STm->do_async_writes = value;
+		if ((options & MT_ST_DEF_WRITES) != 0)
+			STm->defaults_for_writes = value;
+		if ((options & MT_ST_READ_AHEAD) != 0)
+			STm->do_read_ahead = value;
+		if ((options & MT_ST_TWO_FM) != 0)
+			STp->two_fm = value;
+		if ((options & MT_ST_FAST_MTEOM) != 0)
+			STp->fast_mteom = value;
+		if ((options & MT_ST_AUTO_LOCK) != 0)
+			STp->do_auto_lock = value;
+		if ((options & MT_ST_CAN_BSR) != 0)
+			STp->can_bsr = value;
+		if ((options & MT_ST_NO_BLKLIMS) != 0)
+			STp->omit_blklims = value;
+		if ((STp->device)->scsi_level >= SCSI_2 &&
+		    (options & MT_ST_CAN_PARTITIONS) != 0)
+			STp->can_partitions = value;
+		if ((options & MT_ST_SCSI2LOGICAL) != 0)
+			STp->scsi2_logical = value;
+		if ((options & MT_ST_SYSV) != 0)
+			STm->sysv = value;
+#if DEBUG
+		if ((options & MT_ST_DEBUGGING) != 0)
+			debugging = value;
+#endif
+		st_log_options(STp, STm, dev);
+	} else if (code == MT_ST_WRITE_THRESHOLD) {
+		value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
+		if (value < 1 || value > st_buffer_size) {
+			printk(KERN_WARNING "st%d: Write threshold %d too small or too large.\n",
+			       dev, value);
+			return (-EIO);
+		}
+		STp->write_threshold = value;
+		printk(KERN_INFO "st%d: Write threshold set to %d bytes.\n",
+		       dev, value);
+	} else if (code == MT_ST_DEF_BLKSIZE) {
+		value = (options & ~MT_ST_OPTIONS);
+		if (value == ~MT_ST_OPTIONS) {
+			STm->default_blksize = (-1);
+			printk(KERN_INFO "st%d: Default block size disabled.\n", dev);
+		} else {
+			STm->default_blksize = value;
+			printk(KERN_INFO "st%d: Default block size set to %d bytes.\n",
+			       dev, STm->default_blksize);
+		}
+	} else if (code == MT_ST_TIMEOUTS) {
+		value = (options & ~MT_ST_OPTIONS);
+		if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
+			STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
+			printk(KERN_INFO "st%d: Long timeout set to %d seconds.\n", dev,
+			       (value & ~MT_ST_SET_LONG_TIMEOUT));
+		} else {
+			STp->timeout = value * HZ;
+			printk(KERN_INFO "st%d: Normal timeout set to %d seconds.\n", dev,
+			       value);
+		}
+	} else if (code == MT_ST_DEF_OPTIONS) {
+		code = (options & ~MT_ST_CLEAR_DEFAULT);
+		value = (options & MT_ST_CLEAR_DEFAULT);
+		if (code == MT_ST_DEF_DENSITY) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STm->default_density = (-1);
+				printk(KERN_INFO "st%d: Density default disabled.\n", dev);
+			} else {
+				STm->default_density = value & 0xff;
+				printk(KERN_INFO "st%d: Density default set to %x\n",
+				       dev, STm->default_density);
+			}
+		} else if (code == MT_ST_DEF_DRVBUFFER) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STp->default_drvbuffer = 0xff;
+				printk(KERN_INFO "st%d: Drive buffer default disabled.\n", dev);
+			} else {
+				STp->default_drvbuffer = value & 7;
+				printk(KERN_INFO "st%d: Drive buffer default set to %x\n",
+				       dev, STp->default_drvbuffer);
+			}
+		} else if (code == MT_ST_DEF_COMPRESSION) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STm->default_compression = ST_DONT_TOUCH;
+				printk(KERN_INFO "st%d: Compression default disabled.\n", dev);
+			} else {
+				STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+				printk(KERN_INFO "st%d: Compression default set to %x\n",
+				       dev, (value & 1));
+			}
+		}
+	} else
+		return (-EIO);
 
-  scsi_release_command(SCpnt);
-  SCpnt = NULL;
-  STp->compression_changed = TRUE;
-  return 0;
+	return 0;
 }
+
 
+#define COMPRESSION_PAGE        0x0f
+#define COMPRESSION_PAGE_LENGTH 16
+
+#define MODE_HEADER_LENGTH  4
+
+#define DCE_MASK  0x80
+#define DCC_MASK  0x40
+#define RED_MASK  0x60
+
+
+/* Control the compression with mode page 15. Algorithm not changed if zero. */
+static int st_compression(Scsi_Tape * STp, int state)
+{
+	int dev;
+	unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt = NULL;
+
+	if (STp->ready != ST_READY)
+		return (-EIO);
+
+	/* Read the current page contents */
+	memset(cmd, 0, 10);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = COMPRESSION_PAGE;
+	cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	if (SCpnt == NULL)
+		return (-EBUSY);
+	dev = TAPE_NR(SCpnt->request.rq_dev);
+
+	if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
+#endif
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+		return (-EIO);
+	}
+#if DEBUG
+	if (debugging)
+		printk(ST_DEB_MSG "st%d: Compression state is %d.\n", dev,
+		       ((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCE_MASK ? 1 : 0));
+#endif
+
+	/* Check if compression can be changed */
+	if (((STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] & DCC_MASK) == 0) {
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
+#endif
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+		return (-EIO);
+	}
+	/* Do the change */
+	if (state)
+		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] |= DCE_MASK;
+	else
+		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] &= ~DCE_MASK;
+
+	memset(cmd, 0, 10);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = COMPRESSION_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	(STp->buffer)->b_data[0] = 0;	/* Reserved data length */
+	(STp->buffer)->b_data[1] = 0;	/* Reserved media type byte */
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH] &= 0x3f;
+	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+
+	if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
+#endif
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+		return (-EIO);
+	}
+#if DEBUG
+	if (debugging)
+		printk(ST_DEB_MSG "st%d: Compression state changed to %d.\n",
+		       dev, state);
+#endif
+
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+	STp->compression_changed = TRUE;
+	return 0;
+}
 
+
 /* Internal ioctl function */
-	static int
-st_int_ioctl(struct inode * inode,
-	     unsigned int cmd_in, unsigned long arg)
-{
-   int timeout;
-   long ltmp;
-   int i, ioctl_result;
-   int chg_eof = TRUE;
-   unsigned char cmd[10];
-   Scsi_Cmnd * SCpnt;
-   Scsi_Tape * STp;
-   ST_partstat * STps;
-   int fileno, blkno, at_sm, undone, datalen;
-   int dev = TAPE_NR(inode->i_rdev);
-
-   STp = &(scsi_tapes[dev]);
-   if (STp->ready != ST_READY && cmd_in != MTLOAD) {
-     if (STp->ready == ST_NO_TAPE)
-       return (-ENOMEDIUM);
-     else
-       return (-EIO);
-   }
-   timeout = STp->long_timeout;
-   STps = &(STp->ps[STp->partition]);
-   fileno = STps->drv_file;
-   blkno = STps->drv_block;
-   at_sm = STps->at_sm;
-
-   memset(cmd, 0, 10);
-   datalen = 0;
-   switch (cmd_in) {
-     case MTFSFM:
-       chg_eof = FALSE; /* Changed from the FSF after this */
-     case MTFSF:
-       cmd[0] = SPACE;
-       cmd[1] = 0x01; /* Space FileMarks */
-       cmd[2] = (arg >> 16);
-       cmd[3] = (arg >> 8);
-       cmd[4] = arg;
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n",
-		dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
-       if (fileno >= 0)
-	 fileno += arg;
-       blkno = 0;
-       at_sm &= (arg == 0);
-       break;
-     case MTBSFM:
-       chg_eof = FALSE; /* Changed from the FSF after this */
-     case MTBSF:
-       cmd[0] = SPACE;
-       cmd[1] = 0x01; /* Space FileMarks */
-       ltmp = (-arg);
-       cmd[2] = (ltmp >> 16);
-       cmd[3] = (ltmp >> 8);
-       cmd[4] = ltmp;
-#if DEBUG
-       if (debugging) {
-	 if (cmd[2] & 0x80)
-	   ltmp = 0xff000000;
-	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-	 printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n",
-		dev, (-ltmp));
-       }
-#endif
-       if (fileno >= 0)
-	 fileno -= arg;
-       blkno = (-1);  /* We can't know the block number */
-       at_sm &= (arg == 0);
-       break;
-     case MTFSR:
-       cmd[0] = SPACE;
-       cmd[1] = 0x00; /* Space Blocks */
-       cmd[2] = (arg >> 16);
-       cmd[3] = (arg >> 8);
-       cmd[4] = arg;
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev,
-		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
-       if (blkno >= 0)
-	 blkno += arg;
-       at_sm &= (arg == 0);
-       break;
-     case MTBSR:
-       cmd[0] = SPACE;
-       cmd[1] = 0x00; /* Space Blocks */
-       ltmp = (-arg);
-       cmd[2] = (ltmp >> 16);
-       cmd[3] = (ltmp >> 8);
-       cmd[4] = ltmp;
-#if DEBUG
-       if (debugging) {
-	 if (cmd[2] & 0x80)
-	   ltmp = 0xff000000;
-	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-	 printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
-       }
-#endif
-       if (blkno >= 0)
-	 blkno -= arg;
-       at_sm &= (arg == 0);
-       break;
-     case MTFSS:
-       cmd[0] = SPACE;
-       cmd[1] = 0x04; /* Space Setmarks */
-       cmd[2] = (arg >> 16);
-       cmd[3] = (arg >> 8);
-       cmd[4] = arg;
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev,
-		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-#endif
-       if (arg != 0) {
-	 blkno = fileno = (-1);
-	 at_sm = 1;
-       }
-       break;
-     case MTBSS:
-       cmd[0] = SPACE;
-       cmd[1] = 0x04; /* Space Setmarks */
-       ltmp = (-arg);
-       cmd[2] = (ltmp >> 16);
-       cmd[3] = (ltmp >> 8);
-       cmd[4] = ltmp;
-#if DEBUG
-       if (debugging) {
-	 if (cmd[2] & 0x80)
-	   ltmp = 0xff000000;
-	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
-	 printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n",
-		dev, (-ltmp));
-       }
-#endif
-       if (arg != 0) {
-	 blkno = fileno = (-1);
-	 at_sm = 1;
-       }
-       break;
-     case MTWEOF:
-     case MTWSM:
-       if (STp->write_prot)
-	 return (-EACCES);
-       cmd[0] = WRITE_FILEMARKS;
-       if (cmd_in == MTWSM)
-	 cmd[1] = 2;
-       cmd[2] = (arg >> 16);
-       cmd[3] = (arg >> 8);
-       cmd[4] = arg;
-       timeout = STp->timeout;
-#if DEBUG
-       if (debugging) {
-	 if (cmd_in == MTWEOF)
-	   printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev,
-		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-	 else
-	   printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev,
-		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
-       }
-#endif
-       if (fileno >= 0)
-	 fileno += arg;
-       blkno = 0;
-       at_sm = (cmd_in == MTWSM);
-       break;
-     case MTREW:
-       cmd[0] = REZERO_UNIT;
+static int st_int_ioctl(struct inode *inode,
+			unsigned int cmd_in, unsigned long arg)
+{
+	int timeout;
+	long ltmp;
+	int i, ioctl_result;
+	int chg_eof = TRUE;
+	unsigned char cmd[10];
+	Scsi_Cmnd *SCpnt;
+	Scsi_Tape *STp;
+	ST_partstat *STps;
+	int fileno, blkno, at_sm, undone, datalen;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	STp = &(scsi_tapes[dev]);
+	if (STp->ready != ST_READY && cmd_in != MTLOAD) {
+		if (STp->ready == ST_NO_TAPE)
+			return (-ENOMEDIUM);
+		else
+			return (-EIO);
+	}
+	timeout = STp->long_timeout;
+	STps = &(STp->ps[STp->partition]);
+	fileno = STps->drv_file;
+	blkno = STps->drv_block;
+	at_sm = STps->at_sm;
+
+	memset(cmd, 0, 10);
+	datalen = 0;
+	switch (cmd_in) {
+	case MTFSFM:
+		chg_eof = FALSE;	/* Changed from the FSF after this */
+	case MTFSF:
+		cmd[0] = SPACE;
+		cmd[1] = 0x01;	/* Space FileMarks */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n",
+			    dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+		if (fileno >= 0)
+			fileno += arg;
+		blkno = 0;
+		at_sm &= (arg == 0);
+		break;
+	case MTBSFM:
+		chg_eof = FALSE;	/* Changed from the FSF after this */
+	case MTBSF:
+		cmd[0] = SPACE;
+		cmd[1] = 0x01;	/* Space FileMarks */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+#if DEBUG
+		if (debugging) {
+			if (cmd[2] & 0x80)
+				ltmp = 0xff000000;
+			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+			printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n",
+			       dev, (-ltmp));
+		}
+#endif
+		if (fileno >= 0)
+			fileno -= arg;
+		blkno = (-1);	/* We can't know the block number */
+		at_sm &= (arg == 0);
+		break;
+	case MTFSR:
+		cmd[0] = SPACE;
+		cmd[1] = 0x00;	/* Space Blocks */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev,
+			       cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+		if (blkno >= 0)
+			blkno += arg;
+		at_sm &= (arg == 0);
+		break;
+	case MTBSR:
+		cmd[0] = SPACE;
+		cmd[1] = 0x00;	/* Space Blocks */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+#if DEBUG
+		if (debugging) {
+			if (cmd[2] & 0x80)
+				ltmp = 0xff000000;
+			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+			printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
+		}
+#endif
+		if (blkno >= 0)
+			blkno -= arg;
+		at_sm &= (arg == 0);
+		break;
+	case MTFSS:
+		cmd[0] = SPACE;
+		cmd[1] = 0x04;	/* Space Setmarks */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev,
+			       cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+		if (arg != 0) {
+			blkno = fileno = (-1);
+			at_sm = 1;
+		}
+		break;
+	case MTBSS:
+		cmd[0] = SPACE;
+		cmd[1] = 0x04;	/* Space Setmarks */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+#if DEBUG
+		if (debugging) {
+			if (cmd[2] & 0x80)
+				ltmp = 0xff000000;
+			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+			printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n",
+			       dev, (-ltmp));
+		}
+#endif
+		if (arg != 0) {
+			blkno = fileno = (-1);
+			at_sm = 1;
+		}
+		break;
+	case MTWEOF:
+	case MTWSM:
+		if (STp->write_prot)
+			return (-EACCES);
+		cmd[0] = WRITE_FILEMARKS;
+		if (cmd_in == MTWSM)
+			cmd[1] = 2;
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+		timeout = STp->timeout;
+#if DEBUG
+		if (debugging) {
+			if (cmd_in == MTWEOF)
+				printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev,
+				 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+			else
+				printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev,
+				 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+		}
+#endif
+		if (fileno >= 0)
+			fileno += arg;
+		blkno = 0;
+		at_sm = (cmd_in == MTWSM);
+		break;
+	case MTREW:
+		cmd[0] = REZERO_UNIT;
 #if ST_NOWAIT
-       cmd[1] = 1;  /* Don't wait for completion */
-       timeout = STp->timeout;
+		cmd[1] = 1;	/* Don't wait for completion */
+		timeout = STp->timeout;
 #endif
 #if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev);
 #endif
-       fileno = blkno = at_sm = 0 ;
-       break;
-     case MTOFFL:
-     case MTLOAD:
-     case MTUNLOAD:
-       cmd[0] = START_STOP;
-       if (cmd_in == MTLOAD)
-	 cmd[4] |= 1;
-       /*
-        * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
-       */
-       if (cmd_in != MTOFFL &&
-	   arg >= 1 + MT_ST_HPLOADER_OFFSET
-	   && arg <= 6 + MT_ST_HPLOADER_OFFSET) {
-#if DEBUG
-	   if (debugging) {
-	       printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
-		      dev, (cmd[4]) ? "" : "un",
-		      arg - MT_ST_HPLOADER_OFFSET);
-	   }
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTOFFL:
+	case MTLOAD:
+	case MTUNLOAD:
+		cmd[0] = START_STOP;
+		if (cmd_in == MTLOAD)
+			cmd[4] |= 1;
+		/*
+		 * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
+		 */
+		if (cmd_in != MTOFFL &&
+		    arg >= 1 + MT_ST_HPLOADER_OFFSET
+		    && arg <= 6 + MT_ST_HPLOADER_OFFSET) {
+#if DEBUG
+			if (debugging) {
+				printk(ST_DEB_MSG "st%d: Enhanced %sload slot %2ld.\n",
+				       dev, (cmd[4]) ? "" : "un",
+				       arg - MT_ST_HPLOADER_OFFSET);
+			}
 #endif
-	   cmd[3] = arg - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
-       }
+			cmd[3] = arg - MT_ST_HPLOADER_OFFSET;	/* MediaID field of C1553A */
+		}
 #if ST_NOWAIT
-       cmd[1] = 1;  /* Don't wait for completion */
-       timeout = STp->timeout;
+		cmd[1] = 1;	/* Don't wait for completion */
+		timeout = STp->timeout;
 #else
-       timeout = STp->long_timeout;
+		timeout = STp->long_timeout;
 #endif
 #if DEBUG
-       if (debugging) {
-	 if (cmd_in != MTLOAD)
-	   printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
-	 else
-	   printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
-       }
-#endif
-       fileno = blkno = at_sm = 0 ;
-       break;
-     case MTNOP:
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: No op on tape.\n", dev);
-#endif
-       return 0;  /* Should do something ? */
-       break;
-     case MTRETEN:
-       cmd[0] = START_STOP;
+		if (debugging) {
+			if (cmd_in != MTLOAD)
+				printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
+			else
+				printk(ST_DEB_MSG "st%d: Loading tape.\n", dev);
+		}
+#endif
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTNOP:
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: No op on tape.\n", dev);
+#endif
+		return 0;	/* Should do something ? */
+		break;
+	case MTRETEN:
+		cmd[0] = START_STOP;
 #if ST_NOWAIT
-       cmd[1] = 1;  /* Don't wait for completion */
-       timeout = STp->timeout;
+		cmd[1] = 1;	/* Don't wait for completion */
+		timeout = STp->timeout;
 #endif
-       cmd[4] = 3;
+		cmd[4] = 3;
 #if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev);
 #endif
-       fileno = blkno = at_sm = 0;
-       break;
-     case MTEOM:
-       if (!STp->fast_mteom) {
-	 /* space to the end of tape */
-	 ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff);
-	 fileno = STps->drv_file;
-	 if (STps->eof >= ST_EOD_1)
-	   return 0;
-	 /* The next lines would hide the number of spaced FileMarks
-	    That's why I inserted the previous lines. I had no luck
-	    with detecting EOM with FSF, so we go now to EOM.
-	    Joerg Weule */
-       }
-       else
-	 fileno = (-1);
-       cmd[0] = SPACE;
-       cmd[1] = 3;
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev);
-#endif
-       blkno = 0;
-       at_sm = 0;
-       break;
-     case MTERASE:
-       if (STp->write_prot)
-	 return (-EACCES);
-       cmd[0] = ERASE;
-       cmd[1] = 1;  /* To the end of tape */
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTEOM:
+		if (!STp->fast_mteom) {
+			/* space to the end of tape */
+			ioctl_result = st_int_ioctl(inode, MTFSF, 0x3fff);
+			fileno = STps->drv_file;
+			if (STps->eof >= ST_EOD_1)
+				return 0;
+			/* The next lines would hide the number of spaced FileMarks
+			   That's why I inserted the previous lines. I had no luck
+			   with detecting EOM with FSF, so we go now to EOM.
+			   Joerg Weule */
+		} else
+			fileno = (-1);
+		cmd[0] = SPACE;
+		cmd[1] = 3;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev);
+#endif
+		blkno = 0;
+		at_sm = 0;
+		break;
+	case MTERASE:
+		if (STp->write_prot)
+			return (-EACCES);
+		cmd[0] = ERASE;
+		cmd[1] = 1;	/* To the end of tape */
 #if ST_NOWAIT
-       cmd[1] |= 2;  /* Don't wait for completion */
-       timeout = STp->timeout;
+		cmd[1] |= 2;	/* Don't wait for completion */
+		timeout = STp->timeout;
 #else
-       timeout = STp->long_timeout * 8;
+		timeout = STp->long_timeout * 8;
 #endif
 #if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev);
 #endif
-       fileno = blkno = at_sm = 0 ;
-       break;
-     case MTLOCK:
-       chg_eof = FALSE;
-       cmd[0] = ALLOW_MEDIUM_REMOVAL;
-       cmd[4] = SCSI_REMOVAL_PREVENT;
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev);
-#endif;
-       break;
-     case MTUNLOCK:
-       chg_eof = FALSE;
-       cmd[0] = ALLOW_MEDIUM_REMOVAL;
-       cmd[4] = SCSI_REMOVAL_ALLOW;
-#if DEBUG
-       if (debugging)
-	 printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev);
-#endif;
-       break;
-     case MTSETBLK:  /* Set block length */
-     case MTSETDENSITY: /* Set tape density */
-     case MTSETDRVBUFFER: /* Set drive buffering */
-     case SET_DENS_AND_BLK: /* Set density and block size */
-       chg_eof = FALSE;
-       if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
-	 return (-EIO);   /* Not allowed if data in buffer */
-       if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
-	   (arg & MT_ST_BLKSIZE_MASK) != 0 &&
-	   ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
-	    (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
-	    (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) {
-	 printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
-	 return (-EINVAL);
-       }
-       cmd[0] = MODE_SELECT;
-       cmd[4] = datalen = 12;
-
-       memset((STp->buffer)->b_data, 0, 12);
-       if (cmd_in == MTSETDRVBUFFER)
-	 (STp->buffer)->b_data[2] = (arg & 7) << 4;
-       else
-	 (STp->buffer)->b_data[2] =
-	   STp->drv_buffer << 4;
-       (STp->buffer)->b_data[3] = 8;     /* block descriptor length */
-       if (cmd_in == MTSETDENSITY) {
-	 (STp->buffer)->b_data[4] = arg;
-	 STp->density_changed = TRUE;  /* At least we tried ;-) */
-       }
-       else if (cmd_in == SET_DENS_AND_BLK)
-	 (STp->buffer)->b_data[4] = arg >> 24;
-       else
-	 (STp->buffer)->b_data[4] = STp->density;
-       if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
-	 ltmp = arg & MT_ST_BLKSIZE_MASK;
-	 if (cmd_in == MTSETBLK)
-	   STp->blksize_changed = TRUE;  /* At least we tried ;-) */
-       }
-       else
-	 ltmp = STp->block_size;
-       (STp->buffer)->b_data[9] = (ltmp >> 16);
-       (STp->buffer)->b_data[10] = (ltmp >> 8);
-       (STp->buffer)->b_data[11] = ltmp;
-       timeout = STp->timeout;
-#if DEBUG
-       if (debugging) {
-	 if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
-	   printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev,
-		  (STp->buffer)->b_data[9] * 65536 +
-		  (STp->buffer)->b_data[10] * 256 +
-		  (STp->buffer)->b_data[11]);
-	 if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
-	   printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev,
-		  (STp->buffer)->b_data[4]);
-	 if (cmd_in == MTSETDRVBUFFER)
-	   printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev,
-		  ((STp->buffer)->b_data[2] >> 4) & 7);
-       }
-#endif
-       break;
-     default:
-       return (-ENOSYS);
-     }
-
-   SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
-   if (!SCpnt)
-     return (-EBUSY);
-
-   ioctl_result = (STp->buffer)->last_result_fatal;
-
-   if (!ioctl_result) {  /* SCSI command successful */
-     scsi_release_command(SCpnt);
-     SCpnt = NULL;
-     STps->drv_block = blkno;
-     STps->drv_file = fileno;
-     STps->at_sm = at_sm;
-
-     if (cmd_in == MTLOCK)
-       STp->door_locked = ST_LOCKED_EXPLICIT;
-     else if (cmd_in == MTUNLOCK)
-       STp->door_locked = ST_UNLOCKED;
-
-     if (cmd_in == MTBSFM)
-       ioctl_result = st_int_ioctl(inode, MTFSF, 1);
-     else if (cmd_in == MTFSFM)
-       ioctl_result = st_int_ioctl(inode, MTBSF, 1);
-
-     if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
-       STp->block_size = arg & MT_ST_BLKSIZE_MASK;
-       if (STp->block_size != 0)
-	 (STp->buffer)->buffer_blocks =
-	   (STp->buffer)->buffer_size / STp->block_size;
-       (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
-       if (cmd_in == SET_DENS_AND_BLK)
-         STp->density = arg >> MT_ST_DENSITY_SHIFT;
-     }
-     else if (cmd_in == MTSETDRVBUFFER)
-       STp->drv_buffer = (arg & 7);
-     else if (cmd_in == MTSETDENSITY)
-       STp->density = arg;
-
-     if (cmd_in == MTEOM)
-       STps->eof = ST_EOD;
-     else if (cmd_in == MTFSF)
-       STps->eof = ST_FM;
-     else if (chg_eof)
-       STps->eof = ST_NOEOF;
-
-
-     if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
-       STp->rew_at_close = 0;
-     else if (cmd_in == MTLOAD) {
-       STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
-       for (i=0; i < ST_NBR_PARTITIONS; i++) {
-	 STp->ps[i].rw = ST_IDLE;
-	 STp->ps[i].last_block_valid = FALSE;
-       }
-       STp->partition = 0;
-     }
-
-   } else {  /* SCSI command was not completely successful. Don't return
-	        from this block without releasing the SCSI command block! */
-
-     if (SCpnt->sense_buffer[2] & 0x40) {
-       if (cmd_in != MTBSF && cmd_in != MTBSFM &&
-	   cmd_in != MTBSR && cmd_in != MTBSS)
-	   STps->eof = ST_EOM_OK;
-       STps->drv_block = 0;
-     }
-
-     undone = (
-	  (SCpnt->sense_buffer[3] << 24) +
-	  (SCpnt->sense_buffer[4] << 16) +
-	  (SCpnt->sense_buffer[5] << 8) +
-	  SCpnt->sense_buffer[6] );
-     if (cmd_in == MTWEOF &&
-       (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
-       (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
-       ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
-       ioctl_result = 0;  /* EOF written succesfully at EOM */
-       if (fileno >= 0)
-	 fileno++;
-       STps->drv_file = fileno;
-       STps->eof = ST_NOEOF;
-     }
-     else if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) {
-       if (fileno >= 0)
-	 STps->drv_file = fileno - undone ;
-       else
-	 STps->drv_file = fileno;
-       STps->drv_block = 0;
-       STps->eof = ST_NOEOF;
-     }
-     else if ( (cmd_in == MTBSF) || (cmd_in == MTBSFM) ) {
-       if (fileno >= 0)
-         STps->drv_file = fileno + undone ;
-       else
-	 STps->drv_file = fileno;
-       STps->drv_block = 0;
-       STps->eof = ST_NOEOF;
-     }
-     else if (cmd_in == MTFSR) {
-       if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
-	 if (STps->drv_file >= 0)
-	   STps->drv_file++;
-	 STps->drv_block = 0;
-	 STps->eof = ST_FM;
-       }
-       else {
-	 if (blkno >= undone)
-	   STps->drv_block = blkno - undone;
-	 else
-	   STps->drv_block = (-1);
-	 STps->eof = ST_NOEOF;
-       }
-     }
-     else if (cmd_in == MTBSR) {
-       if (SCpnt->sense_buffer[2] & 0x80) { /* Hit filemark */
-	 STps->drv_file--;
-	 STps->drv_block = (-1);
-       }
-       else {
-	 if (blkno >= 0)
-	   STps->drv_block = blkno + undone;
-	 else
-	   STps->drv_block = (-1);
-       }
-       STps->eof = ST_NOEOF;
-     }
-     else if (cmd_in == MTEOM) {
-       STps->drv_file = (-1);
-       STps->drv_block = (-1);
-       STps->eof = ST_EOD;
-     }
-     else if (chg_eof)
-       STps->eof = ST_NOEOF;
-
-     if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
-       STps->eof = ST_EOD;
-
-     if (cmd_in == MTLOCK)
-       STp->door_locked = ST_LOCK_FAILS;
-
-     scsi_release_command(SCpnt);
-     SCpnt = NULL;
-   }
-
-   return ioctl_result;
-}
-
-
-/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
-    structure. */
-
-	static int
-get_location(struct inode * inode, unsigned int *block, int *partition,
-	     int logical)
-{
-    Scsi_Tape *STp;
-    int dev = TAPE_NR(inode->i_rdev);
-    int result;
-    unsigned char scmd[10];
-    Scsi_Cmnd *SCpnt;
-
-    STp = &(scsi_tapes[dev]);
-    if (STp->ready != ST_READY)
-      return (-EIO);
-
-    memset (scmd, 0, 10);
-    if ((STp->device)->scsi_level < SCSI_2) {
-      scmd[0] = QFA_REQUEST_BLOCK;
-      scmd[4] = 3;
-    }
-    else {
-      scmd[0] = READ_POSITION;
-      if (!logical && !STp->scsi2_logical)
-	scmd[1] = 1;
-    }
-    SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
-    if (!SCpnt)
-      return (-EBUSY);
-
-    if ((STp->buffer)->last_result_fatal != 0 ||
-	(STp->device->scsi_level >= SCSI_2 &&
-	 ((STp->buffer)->b_data[0] & 4) != 0)) {
-      *block = *partition = 0;
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev);
-#endif
-      result = (-EIO);
-    }
-    else {
-      result = 0;
-      if ((STp->device)->scsi_level < SCSI_2) {
-	*block = ((STp->buffer)->b_data[0] << 16)
-	+ ((STp->buffer)->b_data[1] << 8)
-	+ (STp->buffer)->b_data[2];
-	*partition = 0;
-      }
-      else {
-	*block = ((STp->buffer)->b_data[4] << 24)
-	  + ((STp->buffer)->b_data[5] << 16)
-	  + ((STp->buffer)->b_data[6] << 8)
-	  + (STp->buffer)->b_data[7];
-	*partition = (STp->buffer)->b_data[1];
-	if (((STp->buffer)->b_data[0] & 0x80) &&
-	    (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */
-	    STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
-      }
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
-	       *block, *partition);
-#endif
-
-    }
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTLOCK:
+		chg_eof = FALSE;
+		cmd[0] = ALLOW_MEDIUM_REMOVAL;
+		cmd[4] = SCSI_REMOVAL_PREVENT;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev);
+#endif	/* ; */
+		break;
+	case MTUNLOCK:
+		chg_eof = FALSE;
+		cmd[0] = ALLOW_MEDIUM_REMOVAL;
+		cmd[4] = SCSI_REMOVAL_ALLOW;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev);
+#endif	/* ; */
+		break;
+	case MTSETBLK:		/* Set block length */
+	case MTSETDENSITY:	/* Set tape density */
+	case MTSETDRVBUFFER:	/* Set drive buffering */
+	case SET_DENS_AND_BLK:	/* Set density and block size */
+		chg_eof = FALSE;
+		if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
+			return (-EIO);	/* Not allowed if data in buffer */
+		if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
+		    (arg & MT_ST_BLKSIZE_MASK) != 0 &&
+		    ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
+		     (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
+		     (arg & MT_ST_BLKSIZE_MASK) > st_buffer_size)) {
+			printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
+			return (-EINVAL);
+		}
+		cmd[0] = MODE_SELECT;
+		cmd[4] = datalen = 12;
+
+		memset((STp->buffer)->b_data, 0, 12);
+		if (cmd_in == MTSETDRVBUFFER)
+			(STp->buffer)->b_data[2] = (arg & 7) << 4;
+		else
+			(STp->buffer)->b_data[2] =
+			    STp->drv_buffer << 4;
+		(STp->buffer)->b_data[3] = 8;	/* block descriptor length */
+		if (cmd_in == MTSETDENSITY) {
+			(STp->buffer)->b_data[4] = arg;
+			STp->density_changed = TRUE;	/* At least we tried ;-) */
+		} else if (cmd_in == SET_DENS_AND_BLK)
+			(STp->buffer)->b_data[4] = arg >> 24;
+		else
+			(STp->buffer)->b_data[4] = STp->density;
+		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+			ltmp = arg & MT_ST_BLKSIZE_MASK;
+			if (cmd_in == MTSETBLK)
+				STp->blksize_changed = TRUE;	/* At least we tried ;-) */
+		} else
+			ltmp = STp->block_size;
+		(STp->buffer)->b_data[9] = (ltmp >> 16);
+		(STp->buffer)->b_data[10] = (ltmp >> 8);
+		(STp->buffer)->b_data[11] = ltmp;
+		timeout = STp->timeout;
+#if DEBUG
+		if (debugging) {
+			if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
+				printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev,
+				       (STp->buffer)->b_data[9] * 65536 +
+				       (STp->buffer)->b_data[10] * 256 +
+				       (STp->buffer)->b_data[11]);
+			if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
+				printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev,
+				       (STp->buffer)->b_data[4]);
+			if (cmd_in == MTSETDRVBUFFER)
+				printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev,
+				    ((STp->buffer)->b_data[2] >> 4) & 7);
+		}
+#endif
+		break;
+	default:
+		return (-ENOSYS);
+	}
+
+	SCpnt = st_do_scsi(NULL, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
+	if (!SCpnt)
+		return (-EBUSY);
+
+	ioctl_result = (STp->buffer)->last_result_fatal;
+
+	if (!ioctl_result) {	/* SCSI command successful */
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+		STps->drv_block = blkno;
+		STps->drv_file = fileno;
+		STps->at_sm = at_sm;
+
+		if (cmd_in == MTLOCK)
+			STp->door_locked = ST_LOCKED_EXPLICIT;
+		else if (cmd_in == MTUNLOCK)
+			STp->door_locked = ST_UNLOCKED;
+
+		if (cmd_in == MTBSFM)
+			ioctl_result = st_int_ioctl(inode, MTFSF, 1);
+		else if (cmd_in == MTFSFM)
+			ioctl_result = st_int_ioctl(inode, MTBSF, 1);
+
+		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+			STp->block_size = arg & MT_ST_BLKSIZE_MASK;
+			if (STp->block_size != 0)
+				(STp->buffer)->buffer_blocks =
+				    (STp->buffer)->buffer_size / STp->block_size;
+			(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
+			if (cmd_in == SET_DENS_AND_BLK)
+				STp->density = arg >> MT_ST_DENSITY_SHIFT;
+		} else if (cmd_in == MTSETDRVBUFFER)
+			STp->drv_buffer = (arg & 7);
+		else if (cmd_in == MTSETDENSITY)
+			STp->density = arg;
+
+		if (cmd_in == MTEOM)
+			STps->eof = ST_EOD;
+		else if (cmd_in == MTFSF)
+			STps->eof = ST_FM;
+		else if (chg_eof)
+			STps->eof = ST_NOEOF;
+
+
+		if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
+			STp->rew_at_close = 0;
+		else if (cmd_in == MTLOAD) {
+			STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+			for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+				STp->ps[i].rw = ST_IDLE;
+				STp->ps[i].last_block_valid = FALSE;
+			}
+			STp->partition = 0;
+		}
+	} else {		/* SCSI command was not completely successful. Don't return
+				   from this block without releasing the SCSI command block! */
 
-    return result;
+		if (SCpnt->sense_buffer[2] & 0x40) {
+			if (cmd_in != MTBSF && cmd_in != MTBSFM &&
+			    cmd_in != MTBSR && cmd_in != MTBSS)
+				STps->eof = ST_EOM_OK;
+			STps->drv_block = 0;
+		}
+		undone = (
+				 (SCpnt->sense_buffer[3] << 24) +
+				 (SCpnt->sense_buffer[4] << 16) +
+				 (SCpnt->sense_buffer[5] << 8) +
+				 SCpnt->sense_buffer[6]);
+		if (cmd_in == MTWEOF &&
+		    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+		    (SCpnt->sense_buffer[2] & 0x4f) == 0x40 &&
+		 ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) {
+			ioctl_result = 0;	/* EOF written succesfully at EOM */
+			if (fileno >= 0)
+				fileno++;
+			STps->drv_file = fileno;
+			STps->eof = ST_NOEOF;
+		} else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) {
+			if (fileno >= 0)
+				STps->drv_file = fileno - undone;
+			else
+				STps->drv_file = fileno;
+			STps->drv_block = 0;
+			STps->eof = ST_NOEOF;
+		} else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
+			if (fileno >= 0)
+				STps->drv_file = fileno + undone;
+			else
+				STps->drv_file = fileno;
+			STps->drv_block = 0;
+			STps->eof = ST_NOEOF;
+		} else if (cmd_in == MTFSR) {
+			if (SCpnt->sense_buffer[2] & 0x80) {	/* Hit filemark */
+				if (STps->drv_file >= 0)
+					STps->drv_file++;
+				STps->drv_block = 0;
+				STps->eof = ST_FM;
+			} else {
+				if (blkno >= undone)
+					STps->drv_block = blkno - undone;
+				else
+					STps->drv_block = (-1);
+				STps->eof = ST_NOEOF;
+			}
+		} else if (cmd_in == MTBSR) {
+			if (SCpnt->sense_buffer[2] & 0x80) {	/* Hit filemark */
+				STps->drv_file--;
+				STps->drv_block = (-1);
+			} else {
+				if (blkno >= 0)
+					STps->drv_block = blkno + undone;
+				else
+					STps->drv_block = (-1);
+			}
+			STps->eof = ST_NOEOF;
+		} else if (cmd_in == MTEOM) {
+			STps->drv_file = (-1);
+			STps->drv_block = (-1);
+			STps->eof = ST_EOD;
+		} else if (chg_eof)
+			STps->eof = ST_NOEOF;
+
+		if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+			STps->eof = ST_EOD;
+
+		if (cmd_in == MTLOCK)
+			STp->door_locked = ST_LOCK_FAILS;
+
+		scsi_release_command(SCpnt);
+		SCpnt = NULL;
+	}
+
+	return ioctl_result;
+}
+
+
+/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
+   structure. */
+
+static int get_location(struct inode *inode, unsigned int *block, int *partition,
+			int logical)
+{
+	Scsi_Tape *STp;
+	int dev = TAPE_NR(inode->i_rdev);
+	int result;
+	unsigned char scmd[10];
+	Scsi_Cmnd *SCpnt;
+
+	STp = &(scsi_tapes[dev]);
+	if (STp->ready != ST_READY)
+		return (-EIO);
+
+	memset(scmd, 0, 10);
+	if ((STp->device)->scsi_level < SCSI_2) {
+		scmd[0] = QFA_REQUEST_BLOCK;
+		scmd[4] = 3;
+	} else {
+		scmd[0] = READ_POSITION;
+		if (!logical && !STp->scsi2_logical)
+			scmd[1] = 1;
+	}
+	SCpnt = st_do_scsi(NULL, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
+	if (!SCpnt)
+		return (-EBUSY);
+
+	if ((STp->buffer)->last_result_fatal != 0 ||
+	    (STp->device->scsi_level >= SCSI_2 &&
+	     ((STp->buffer)->b_data[0] & 4) != 0)) {
+		*block = *partition = 0;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev);
+#endif
+		result = (-EIO);
+	} else {
+		result = 0;
+		if ((STp->device)->scsi_level < SCSI_2) {
+			*block = ((STp->buffer)->b_data[0] << 16)
+			    + ((STp->buffer)->b_data[1] << 8)
+			    + (STp->buffer)->b_data[2];
+			*partition = 0;
+		} else {
+			*block = ((STp->buffer)->b_data[4] << 24)
+			    + ((STp->buffer)->b_data[5] << 16)
+			    + ((STp->buffer)->b_data[6] << 8)
+			    + (STp->buffer)->b_data[7];
+			*partition = (STp->buffer)->b_data[1];
+			if (((STp->buffer)->b_data[0] & 0x80) &&
+			    (STp->buffer)->b_data[1] == 0)	/* BOP of partition 0 */
+				STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
+		}
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Got tape pos. blk %d part %d.\n", dev,
+			       *block, *partition);
+#endif
+
+	}
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	return result;
 }
 
 
 /* Set the tape block and partition. Negative partition means that only the
    block should be set in vendor specific way. */
-	static int
-set_location(struct inode * inode, unsigned int block, int partition,
-	     int logical)
-{
-    Scsi_Tape *STp;
-    ST_partstat *STps;
-    int dev = TAPE_NR(inode->i_rdev);
-    int result, p;
-    unsigned int blk;
-    int timeout;
-    unsigned char scmd[10];
-    Scsi_Cmnd *SCpnt;
-
-    STp = &(scsi_tapes[dev]);
-    if (STp->ready != ST_READY)
-      return (-EIO);
-    timeout = STp->long_timeout;
-    STps = &(STp->ps[STp->partition]);
-
-#if DEBUG
-    if (debugging)
-      printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n",
-	     dev, block, partition);
-    if (partition < 0)
-      return (-EIO);
-#endif
-
-    /* Update the location at the partition we are leaving */
-    if ((!STp->can_partitions && partition != 0) ||
-	partition >= ST_NBR_PARTITIONS)
-      return (-EINVAL);
-    if (partition != STp->partition) {
-      if (get_location(inode, &blk, &p, 1))
-	STps->last_block_valid = FALSE;
-      else {
-	STps->last_block_valid = TRUE;
-	STps->last_block_visited = blk;
+static int set_location(struct inode *inode, unsigned int block, int partition,
+			int logical)
+{
+	Scsi_Tape *STp;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+	int result, p;
+	unsigned int blk;
+	int timeout;
+	unsigned char scmd[10];
+	Scsi_Cmnd *SCpnt;
+
+	STp = &(scsi_tapes[dev]);
+	if (STp->ready != ST_READY)
+		return (-EIO);
+	timeout = STp->long_timeout;
+	STps = &(STp->ps[STp->partition]);
+
 #if DEBUG
 	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n",
-		 dev, blk, STp->partition);
+		printk(ST_DEB_MSG "st%d: Setting block to %d and partition to %d.\n",
+		       dev, block, partition);
+	if (partition < 0)
+		return (-EIO);
+#endif
+
+	/* Update the location at the partition we are leaving */
+	if ((!STp->can_partitions && partition != 0) ||
+	    partition >= ST_NBR_PARTITIONS)
+		return (-EINVAL);
+	if (partition != STp->partition) {
+		if (get_location(inode, &blk, &p, 1))
+			STps->last_block_valid = FALSE;
+		else {
+			STps->last_block_valid = TRUE;
+			STps->last_block_visited = blk;
+#if DEBUG
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Visited block %d for partition %d saved.\n",
+				       dev, blk, STp->partition);
 #endif
-      }
-    }
-
-    memset (scmd, 0, 10);
-    if ((STp->device)->scsi_level < SCSI_2) {
-      scmd[0] = QFA_SEEK_BLOCK;
-      scmd[2] = (block >> 16);
-      scmd[3] = (block >> 8);
-      scmd[4] = block;
-      scmd[5] = 0;
-    }
-    else {
-      scmd[0] = SEEK_10;
-      scmd[3] = (block >> 24);
-      scmd[4] = (block >> 16);
-      scmd[5] = (block >> 8);
-      scmd[6] = block;
-      if (!logical && !STp->scsi2_logical)
-	scmd[1] = 4;
-      if (STp->partition != partition) {
-	scmd[1] |= 2;
-	scmd[8] = partition;
+		}
+	}
+	memset(scmd, 0, 10);
+	if ((STp->device)->scsi_level < SCSI_2) {
+		scmd[0] = QFA_SEEK_BLOCK;
+		scmd[2] = (block >> 16);
+		scmd[3] = (block >> 8);
+		scmd[4] = block;
+		scmd[5] = 0;
+	} else {
+		scmd[0] = SEEK_10;
+		scmd[3] = (block >> 24);
+		scmd[4] = (block >> 16);
+		scmd[5] = (block >> 8);
+		scmd[6] = block;
+		if (!logical && !STp->scsi2_logical)
+			scmd[1] = 4;
+		if (STp->partition != partition) {
+			scmd[1] |= 2;
+			scmd[8] = partition;
 #if DEBUG
-	if (debugging)
-	  printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n",
-		 dev, STp->partition, partition);
+			if (debugging)
+				printk(ST_DEB_MSG "st%d: Trying to change partition from %d to %d\n",
+				       dev, STp->partition, partition);
 #endif
-      }
-     }
+		}
+	}
 #if ST_NOWAIT
-    scmd[1] |= 1;  /* Don't wait for completion */
-    timeout = STp->timeout;
+	scmd[1] |= 1;		/* Don't wait for completion */
+	timeout = STp->timeout;
 #endif
 
-    SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
-    if (!SCpnt)
-      return (-EBUSY);
-
-    STps->drv_block = STps->drv_file = (-1);
-    STps->eof = ST_NOEOF;
-    if ((STp->buffer)->last_result_fatal != 0) {
-      result = (-EIO);
-      if (STp->can_partitions &&
-	  (STp->device)->scsi_level >= SCSI_2 &&
-	  (p = find_partition(inode)) >= 0)
-	STp->partition = p;
-    }
-    else {
-      if (STp->can_partitions) {
-	STp->partition = partition;
-	STps = &(STp->ps[partition]);
-	if (!STps->last_block_valid ||
-	    STps->last_block_visited != block) {
-	  STps->at_sm = 0;
-	  STps->rw = ST_IDLE;
+	SCpnt = st_do_scsi(NULL, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
+	if (!SCpnt)
+		return (-EBUSY);
+
+	STps->drv_block = STps->drv_file = (-1);
+	STps->eof = ST_NOEOF;
+	if ((STp->buffer)->last_result_fatal != 0) {
+		result = (-EIO);
+		if (STp->can_partitions &&
+		    (STp->device)->scsi_level >= SCSI_2 &&
+		    (p = find_partition(inode)) >= 0)
+			STp->partition = p;
+	} else {
+		if (STp->can_partitions) {
+			STp->partition = partition;
+			STps = &(STp->ps[partition]);
+			if (!STps->last_block_valid ||
+			    STps->last_block_visited != block) {
+				STps->at_sm = 0;
+				STps->rw = ST_IDLE;
+			}
+		} else
+			STps->at_sm = 0;
+		if (block == 0)
+			STps->drv_block = STps->drv_file = 0;
+		result = 0;
 	}
-      }
-      else
-	STps->at_sm = 0;
-      if (block == 0)
-	STps->drv_block = STps->drv_file = 0;
-      result = 0;
-    }
 
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
 
-    return result;
+	return result;
 }
 
 
 /* Find the current partition number for the drive status. Called from open and
    returns either partition number of negative error code. */
-	static int
-find_partition(struct inode *inode)
+static int find_partition(struct inode *inode)
 {
-    int i, partition;
-    unsigned int block;
+	int i, partition;
+	unsigned int block;
 
-    if ((i = get_location(inode, &block, &partition, 1)) < 0)
-      return i;
-    if (partition >= ST_NBR_PARTITIONS)
-      return (-EIO);
-    return partition;
+	if ((i = get_location(inode, &block, &partition, 1)) < 0)
+		return i;
+	if (partition >= ST_NBR_PARTITIONS)
+		return (-EIO);
+	return partition;
 }
 
 
 /* Change the partition if necessary */
-	static int
-update_partition(struct inode * inode)
+static int update_partition(struct inode *inode)
 {
-    int dev = TAPE_NR(inode->i_rdev);
-    Scsi_Tape *STp;
-    ST_partstat *STps;
-
-    STp = &(scsi_tapes[dev]);
-    if (STp->partition == STp->new_partition)
-      return 0;
-    STps = &(STp->ps[STp->new_partition]);
-    if (!STps->last_block_valid)
-      STps->last_block_visited = 0;
-    return set_location(inode, STps->last_block_visited, STp->new_partition, 1);
+	int dev = TAPE_NR(inode->i_rdev);
+	Scsi_Tape *STp;
+	ST_partstat *STps;
+
+	STp = &(scsi_tapes[dev]);
+	if (STp->partition == STp->new_partition)
+		return 0;
+	STps = &(STp->ps[STp->new_partition]);
+	if (!STps->last_block_valid)
+		STps->last_block_visited = 0;
+	return set_location(inode, STps->last_block_visited, STp->new_partition, 1);
 }
-
-/* Functions for reading and writing the medium partition mode page. These
+
+/* Functions for reading and writing the medium partition mode page. These
    seem to work with Wangtek 6200HS and HP C1533A. */
 
 #define PART_PAGE   0x11
@@ -2736,656 +2631,635 @@
 
 /* Get the number of partitions on the tape. As a side effect reads the
    mode page into the tape buffer. */
-	static int
-nbr_partitions(struct inode * inode)
+static int nbr_partitions(struct inode *inode)
 {
-    int dev = TAPE_NR(inode->i_rdev), result;
-    Scsi_Tape *STp;
-    Scsi_Cmnd * SCpnt = NULL;
-    unsigned char cmd[10];
-
-    STp = &(scsi_tapes[dev]);
-    if (STp->ready != ST_READY)
-      return (-EIO);
-
-    memset ((void *) &cmd[0], 0, 10);
-    cmd[0] = MODE_SENSE;
-    cmd[1] = 8;   /* Page format */
-    cmd[2] = PART_PAGE;
-    cmd[4] = 200;
-
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE);
-    if (SCpnt == NULL)
-      return (-EBUSY);
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if ((STp->buffer)->last_result_fatal != 0) {
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev);
-#endif
-      result = (-EIO);
-    }
-    else {
-      result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1;
+	int dev = TAPE_NR(inode->i_rdev), result;
+	Scsi_Tape *STp;
+	Scsi_Cmnd *SCpnt = NULL;
+	unsigned char cmd[10];
+
+	STp = &(scsi_tapes[dev]);
+	if (STp->ready != ST_READY)
+		return (-EIO);
+
+	memset((void *) &cmd[0], 0, 10);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;		/* Page format */
+	cmd[2] = PART_PAGE;
+	cmd[4] = 200;
+
+	SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES, TRUE);
+	if (SCpnt == NULL)
+		return (-EBUSY);
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+
+	if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Can't read medium partition page.\n", dev);
+#endif
+		result = (-EIO);
+	} else {
+		result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] + 1;
 #if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result);
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Number of partitions %d.\n", dev, result);
 #endif
-    }
+	}
 
-    return result;
+	return result;
 }
 
 
 /* Partition the tape into two partitions if size > 0 or one partition if
    size == 0 */
-	static int
-partition_tape(struct inode * inode, int size)
+static int partition_tape(struct inode *inode, int size)
 {
-    int dev = TAPE_NR(inode->i_rdev), result;
-    int length;
-    Scsi_Tape *STp;
-    Scsi_Cmnd * SCpnt = NULL;
-    unsigned char cmd[10], *bp;
-
-    if ((result = nbr_partitions(inode)) < 0)
-      return result;
-    STp = &(scsi_tapes[dev]);
-
-    /* The mode page is in the buffer. Let's modify it and write it. */
-    bp = &((STp->buffer)->b_data[0]);
-    if (size <= 0) {
-      length = 8;
-      bp[MODE_HEADER_LENGTH + 3] = 0;
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev);
-#endif
-    }
-    else {
-      length = 10;
-      bp[MODE_HEADER_LENGTH + 3] = 1;
-      bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff;
-      bp[MODE_HEADER_LENGTH + 9] = size & 0xff;
-#if DEBUG
-      if (debugging)
-	printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n",
-	       dev, size);
-#endif
-    }
-    bp[MODE_HEADER_LENGTH + 6] = 0;
-    bp[MODE_HEADER_LENGTH + 7] = 0;
-    bp[MODE_HEADER_LENGTH + 4] = 0x30;   /* IDP | PSUM = MB */
-
-    bp[0] = 0;
-    bp[1] = 0;
-    bp[MODE_HEADER_LENGTH] &= 0x3f;
-    bp[MODE_HEADER_LENGTH + 1] = length - 2;
-
-    memset(cmd, 0, 10);
-    cmd[0] = MODE_SELECT;
-    cmd[1] = 0x10;
-    cmd[4] = length + MODE_HEADER_LENGTH;
-
-    SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout,
-		       MAX_READY_RETRIES, TRUE);
-    if (SCpnt == NULL)
-      return (-EBUSY);
-    scsi_release_command(SCpnt);
-    SCpnt = NULL;
-
-    if ((STp->buffer)->last_result_fatal != 0) {
-      printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
-      result = (-EIO);
-    }
-    else
-      result = 0;
+	int dev = TAPE_NR(inode->i_rdev), result;
+	int length;
+	Scsi_Tape *STp;
+	Scsi_Cmnd *SCpnt = NULL;
+	unsigned char cmd[10], *bp;
+
+	if ((result = nbr_partitions(inode)) < 0)
+		return result;
+	STp = &(scsi_tapes[dev]);
+
+	/* The mode page is in the buffer. Let's modify it and write it. */
+	bp = &((STp->buffer)->b_data[0]);
+	if (size <= 0) {
+		length = 8;
+		bp[MODE_HEADER_LENGTH + 3] = 0;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Formatting tape with one partition.\n", dev);
+#endif
+	} else {
+		length = 10;
+		bp[MODE_HEADER_LENGTH + 3] = 1;
+		bp[MODE_HEADER_LENGTH + 8] = (size >> 8) & 0xff;
+		bp[MODE_HEADER_LENGTH + 9] = size & 0xff;
+#if DEBUG
+		if (debugging)
+			printk(ST_DEB_MSG "st%d: Formatting tape with two partition (1 = %d MB).\n",
+			       dev, size);
+#endif
+	}
+	bp[MODE_HEADER_LENGTH + 6] = 0;
+	bp[MODE_HEADER_LENGTH + 7] = 0;
+	bp[MODE_HEADER_LENGTH + 4] = 0x30;	/* IDP | PSUM = MB */
+
+	bp[0] = 0;
+	bp[1] = 0;
+	bp[MODE_HEADER_LENGTH] &= 0x3f;
+	bp[MODE_HEADER_LENGTH + 1] = length - 2;
 
-    return result;
-}
+	memset(cmd, 0, 10);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = length + MODE_HEADER_LENGTH;
+
+	SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout,
+			   MAX_READY_RETRIES, TRUE);
+	if (SCpnt == NULL)
+		return (-EBUSY);
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
 
+	if ((STp->buffer)->last_result_fatal != 0) {
+		printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
+		result = (-EIO);
+	} else
+		result = 0;
 
+	return result;
+}
 
+
+
 /* The ioctl command */
-	static int
-st_ioctl(struct inode * inode,struct file * file,
-	 unsigned int cmd_in, unsigned long arg)
-{
-   int i, cmd_nr, cmd_type, bt;
-   unsigned int blk;
-   struct mtop mtc;
-   struct mtpos mt_pos;
-   Scsi_Tape *STp;
-   ST_mode *STm;
-   ST_partstat *STps;
-   int dev = TAPE_NR(inode->i_rdev);
-
-   STp = &(scsi_tapes[dev]);
-#if DEBUG
-   if (debugging && !STp->in_use) {
-     printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
-     return (-EIO);
-   }
-#endif
-   STm = &(STp->modes[STp->current_mode]);
-   STps = &(STp->ps[STp->partition]);
-
-    /*
-     * If we are in the middle of error recovery, don't let anyone
-     * else try and use this device.  Also, if error recovery fails, it
-     * may try and take the device offline, in which case all further
-     * access to the device is prohibited.
-     */
-    if( !scsi_block_when_processing_errors(STp->device) ) {
-        return -ENXIO;
-    }
-
-   cmd_type = _IOC_TYPE(cmd_in);
-   cmd_nr   = _IOC_NR(cmd_in);
-
-   if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
-     if (_IOC_SIZE(cmd_in) != sizeof(mtc))
-       return (-EINVAL);
-
-     i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop));
-     if (i)
-	 return (-EFAULT);
-
-     if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
-       printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
-       return (-EPERM);
-     }
-     if (!STm->defined &&
-	 (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0))
-       return (-ENXIO);
-
-     if (!(STp->device)->was_reset) {
-
-       if (STps->eof == ST_FM_HIT) {
-	 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
-	   mtc.mt_count -= 1;
-	   if (STps->drv_file >= 0)
-	     STps->drv_file += 1;
-	 }
-	 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
-	   mtc.mt_count += 1;
-	   if (STps->drv_file >= 0)
-	     STps->drv_file += 1;
-	 }
-       }
-
-       if (mtc.mt_op == MTSEEK) {
-	   /* Old position must be restored if partition will be changed */
-	   i = !STp->can_partitions ||
-	       (STp->new_partition != STp->partition);
-       }
-       else {
-	   i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
-	       mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
-	       mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
-	       mtc.mt_op == MTCOMPRESSION;
-       }
-       i = flush_buffer(inode, file, i);
-       if (i < 0)
-	 return i;
-     }
-     else {
-       /*
-	* If there was a bus reset, block further access
-	* to this device.  If the user wants to rewind the tape,
-	* then reset the flag and allow access again.
-	*/
-       if(mtc.mt_op != MTREW &&
-	  mtc.mt_op != MTOFFL &&
-	  mtc.mt_op != MTRETEN &&
-	  mtc.mt_op != MTERASE &&
-	  mtc.mt_op != MTSEEK &&
-	  mtc.mt_op != MTEOM)
-	 return (-EIO);
-       STp->device->was_reset = 0;
-       if (STp->door_locked != ST_UNLOCKED &&
-	   STp->door_locked != ST_LOCK_FAILS) {
-	 if (st_int_ioctl(inode, MTLOCK, 0)) {
-	   printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n",
-		  dev);
-	   STp->door_locked = ST_UNLOCKED;
-	 }
-       }
-     }
-
-     if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
-	 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
-	 mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
-       STps->rw = ST_IDLE;  /* Prevent automatic WEOF and fsf */
-
-     if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
-       st_int_ioctl(inode, MTUNLOCK, 0);  /* Ignore result! */
-
-     if (mtc.mt_op == MTSETDRVBUFFER &&
-	 (mtc.mt_count & MT_ST_OPTIONS) != 0)
-       return st_set_options(inode, mtc.mt_count);
-     if (mtc.mt_op == MTSETPART) {
-       if (!STp->can_partitions ||
-	   mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
-	 return (-EINVAL);
-       if (mtc.mt_count >= STp->nbr_partitions &&
-	   (STp->nbr_partitions = nbr_partitions(inode)) < 0)
-	 return (-EIO);
-       if (mtc.mt_count >= STp->nbr_partitions)
-	 return (-EINVAL);
-       STp->new_partition = mtc.mt_count;
-       return 0;
-     }
-     if (mtc.mt_op == MTMKPART) {
-       if (!STp->can_partitions)
-	 return (-EINVAL);
-       if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 ||
-	   (i = partition_tape(inode, mtc.mt_count)) < 0)
-	 return i;
-       for (i=0; i < ST_NBR_PARTITIONS; i++) {
-	 STp->ps[i].rw = ST_IDLE;
-	 STp->ps[i].at_sm = 0;
-	 STp->ps[i].last_block_valid = FALSE;
-       }
-       STp->partition = STp->new_partition = 0;
-       STp->nbr_partitions = 1;  /* Bad guess ?-) */
-       STps->drv_block = STps->drv_file = 0;
-       return 0;
-     }
-     if (mtc.mt_op == MTSEEK) {
-       i = set_location(inode, mtc.mt_count, STp->new_partition, 0);
-       if (!STp->can_partitions)
-	   STp->ps[0].rw = ST_IDLE;
-       return i;
-     }
-     if (STp->can_partitions && STp->ready == ST_READY &&
-	 (i = update_partition(inode)) < 0)
-       return i;
-     if (mtc.mt_op == MTCOMPRESSION)
-       return st_compression(STp, (mtc.mt_count & 1));
-     else
-       return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count);
-   }
-
-   if (!STm->defined)
-     return (-ENXIO);
-
-   if ((i = flush_buffer(inode, file, FALSE)) < 0)
-     return i;
-   if (STp->can_partitions &&
-       (i = update_partition(inode)) < 0)
-     return i;
-
-   if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
-
-     if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
-       return (-EINVAL);
-
-     (STp->mt_status)->mt_dsreg =
-       ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
-       ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
-     (STp->mt_status)->mt_blkno = STps->drv_block;
-     (STp->mt_status)->mt_fileno = STps->drv_file;
-     if (STp->block_size != 0) {
-       if (STps->rw == ST_WRITING)
-	 (STp->mt_status)->mt_blkno +=
-	   (STp->buffer)->buffer_bytes / STp->block_size;
-       else if (STps->rw == ST_READING)
-	 (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes +
-	   STp->block_size - 1) / STp->block_size;
-     }
-
-     (STp->mt_status)->mt_gstat = 0;
-     if (STp->drv_write_prot)
-       (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
-     if ((STp->mt_status)->mt_blkno == 0) {
-       if ((STp->mt_status)->mt_fileno == 0)
-	 (STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff);
-       else
-	 (STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff);
-     }
-     (STp->mt_status)->mt_resid = STp->partition;
-     if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
-       (STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
-     else if (STps->eof >= ST_EOM_OK)
-       (STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
-     if (STp->density == 1)
-       (STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
-     else if (STp->density == 2)
-       (STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff);
-     else if (STp->density == 3)
-       (STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff);
-     if (STp->ready == ST_READY)
-       (STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff);
-     if (STp->ready == ST_NO_TAPE)
-       (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
-     if (STps->at_sm)
-       (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
-     if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
-	 STp->drv_buffer != 0)
-       (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff);
-
-     i = copy_to_user((char *)arg, (char *)(STp->mt_status),
-		      sizeof(struct mtget));
-     if (i)
-	 return (-EFAULT);
-
-     (STp->mt_status)->mt_erreg = 0;  /* Clear after read */
-     return 0;
-   } /* End of MTIOCGET */
-
-   if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
-     if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
-       return (-EINVAL);
-     if ((i = get_location(inode, &blk, &bt, 0)) < 0)
-       return i;
-     mt_pos.mt_blkno = blk;
-     i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
-     if (i)
-	 return (-EFAULT);
-     return 0;
-   }
+static int st_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd_in, unsigned long arg)
+{
+	int i, cmd_nr, cmd_type, bt;
+	unsigned int blk;
+	struct mtop mtc;
+	struct mtpos mt_pos;
+	Scsi_Tape *STp;
+	ST_mode *STm;
+	ST_partstat *STps;
+	int dev = TAPE_NR(inode->i_rdev);
+
+	STp = &(scsi_tapes[dev]);
+#if DEBUG
+	if (debugging && !STp->in_use) {
+		printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
+		return (-EIO);
+	}
+#endif
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
 
-   return scsi_ioctl(STp->device, cmd_in, (void *) arg);
-}
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(STp->device)) {
+		return -ENXIO;
+	}
+	cmd_type = _IOC_TYPE(cmd_in);
+	cmd_nr = _IOC_NR(cmd_in);
 
+	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
+		if (_IOC_SIZE(cmd_in) != sizeof(mtc))
+			return (-EINVAL);
+
+		i = copy_from_user((char *) &mtc, (char *) arg, sizeof(struct mtop));
+		if (i)
+			return (-EFAULT);
+
+		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
+			printk(KERN_WARNING "st%d: MTSETDRVBUFFER only allowed for root.\n", dev);
+			return (-EPERM);
+		}
+		if (!STm->defined &&
+		    (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0))
+			return (-ENXIO);
+
+		if (!(STp->device)->was_reset) {
+
+			if (STps->eof == ST_FM_HIT) {
+				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || mtc.mt_op == MTEOM) {
+					mtc.mt_count -= 1;
+					if (STps->drv_file >= 0)
+						STps->drv_file += 1;
+				} else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
+					mtc.mt_count += 1;
+					if (STps->drv_file >= 0)
+						STps->drv_file += 1;
+				}
+			}
+			if (mtc.mt_op == MTSEEK) {
+				/* Old position must be restored if partition will be changed */
+				i = !STp->can_partitions ||
+				    (STp->new_partition != STp->partition);
+			} else {
+				i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+				    mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
+				    mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
+				    mtc.mt_op == MTCOMPRESSION;
+			}
+			i = flush_buffer(inode, file, i);
+			if (i < 0)
+				return i;
+		} else {
+			/*
+			 * If there was a bus reset, block further access
+			 * to this device.  If the user wants to rewind the tape,
+			 * then reset the flag and allow access again.
+			 */
+			if (mtc.mt_op != MTREW &&
+			    mtc.mt_op != MTOFFL &&
+			    mtc.mt_op != MTRETEN &&
+			    mtc.mt_op != MTERASE &&
+			    mtc.mt_op != MTSEEK &&
+			    mtc.mt_op != MTEOM)
+				return (-EIO);
+			STp->device->was_reset = 0;
+			if (STp->door_locked != ST_UNLOCKED &&
+			    STp->door_locked != ST_LOCK_FAILS) {
+				if (st_int_ioctl(inode, MTLOCK, 0)) {
+					printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n",
+					       dev);
+					STp->door_locked = ST_UNLOCKED;
+				}
+			}
+		}
+
+		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
+		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
+		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
+			STps->rw = ST_IDLE;	/* Prevent automatic WEOF and fsf */
+
+		if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
+			st_int_ioctl(inode, MTUNLOCK, 0);	/* Ignore result! */
+
+		if (mtc.mt_op == MTSETDRVBUFFER &&
+		    (mtc.mt_count & MT_ST_OPTIONS) != 0)
+			return st_set_options(inode, mtc.mt_count);
+		if (mtc.mt_op == MTSETPART) {
+			if (!STp->can_partitions ||
+			    mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
+				return (-EINVAL);
+			if (mtc.mt_count >= STp->nbr_partitions &&
+			(STp->nbr_partitions = nbr_partitions(inode)) < 0)
+				return (-EIO);
+			if (mtc.mt_count >= STp->nbr_partitions)
+				return (-EINVAL);
+			STp->new_partition = mtc.mt_count;
+			return 0;
+		}
+		if (mtc.mt_op == MTMKPART) {
+			if (!STp->can_partitions)
+				return (-EINVAL);
+			if ((i = st_int_ioctl(inode, MTREW, 0)) < 0 ||
+			    (i = partition_tape(inode, mtc.mt_count)) < 0)
+				return i;
+			for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+				STp->ps[i].rw = ST_IDLE;
+				STp->ps[i].at_sm = 0;
+				STp->ps[i].last_block_valid = FALSE;
+			}
+			STp->partition = STp->new_partition = 0;
+			STp->nbr_partitions = 1;	/* Bad guess ?-) */
+			STps->drv_block = STps->drv_file = 0;
+			return 0;
+		}
+		if (mtc.mt_op == MTSEEK) {
+			i = set_location(inode, mtc.mt_count, STp->new_partition, 0);
+			if (!STp->can_partitions)
+				STp->ps[0].rw = ST_IDLE;
+			return i;
+		}
+		if (STp->can_partitions && STp->ready == ST_READY &&
+		    (i = update_partition(inode)) < 0)
+			return i;
+		if (mtc.mt_op == MTCOMPRESSION)
+			return st_compression(STp, (mtc.mt_count & 1));
+		else
+			return st_int_ioctl(inode, mtc.mt_op, mtc.mt_count);
+	}
+	if (!STm->defined)
+		return (-ENXIO);
+
+	if ((i = flush_buffer(inode, file, FALSE)) < 0)
+		return i;
+	if (STp->can_partitions &&
+	    (i = update_partition(inode)) < 0)
+		return i;
+
+	if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
+			 return (-EINVAL);
+
+		(STp->mt_status)->mt_dsreg =
+		    ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
+		    ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
+		(STp->mt_status)->mt_blkno = STps->drv_block;
+		(STp->mt_status)->mt_fileno = STps->drv_file;
+		if (STp->block_size != 0) {
+			if (STps->rw == ST_WRITING)
+				(STp->mt_status)->mt_blkno +=
+				    (STp->buffer)->buffer_bytes / STp->block_size;
+			else if (STps->rw == ST_READING)
+				(STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes +
+				  STp->block_size - 1) / STp->block_size;
+		}
+		(STp->mt_status)->mt_gstat = 0;
+		if (STp->drv_write_prot)
+			(STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff);
+		if ((STp->mt_status)->mt_blkno == 0) {
+			if ((STp->mt_status)->mt_fileno == 0)
+				(STp->mt_status)->mt_gstat |= GMT_BOT(0xffffffff);
+			else
+				(STp->mt_status)->mt_gstat |= GMT_EOF(0xffffffff);
+		}
+		(STp->mt_status)->mt_resid = STp->partition;
+		if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
+			(STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
+		else if (STps->eof >= ST_EOM_OK)
+			(STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
+		if (STp->density == 1)
+			(STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
+		else if (STp->density == 2)
+			(STp->mt_status)->mt_gstat |= GMT_D_1600(0xffffffff);
+		else if (STp->density == 3)
+			(STp->mt_status)->mt_gstat |= GMT_D_6250(0xffffffff);
+		if (STp->ready == ST_READY)
+			(STp->mt_status)->mt_gstat |= GMT_ONLINE(0xffffffff);
+		if (STp->ready == ST_NO_TAPE)
+			(STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff);
+		if (STps->at_sm)
+			(STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff);
+		if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
+		    STp->drv_buffer != 0)
+			(STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+
+		i = copy_to_user((char *) arg, (char *) (STp->mt_status),
+				 sizeof(struct mtget));
+		if (i)
+			return (-EFAULT);
+
+		(STp->mt_status)->mt_erreg = 0;		/* Clear after read */
+		return 0;
+	}			/* End of MTIOCGET */
+	if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
+			 return (-EINVAL);
+		if ((i = get_location(inode, &blk, &bt, 0)) < 0)
+			return i;
+		mt_pos.mt_blkno = blk;
+		i = copy_to_user((char *) arg, (char *) (&mt_pos), sizeof(struct mtpos));
+		if (i)
+			return (-EFAULT);
+		return 0;
+	}
+	return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+}
 
+
 /* Try to allocate a new tape buffer */
-	static ST_buffer *
-new_tape_buffer( int from_initialization, int need_dma )
+static ST_buffer *
+ new_tape_buffer(int from_initialization, int need_dma)
 {
-  int i, priority, b_size, got = 0, segs = 0;
-  ST_buffer *tb;
+	int i, priority, b_size, got = 0, segs = 0;
+	ST_buffer *tb;
 
-  if (st_nbr_buffers >= st_template.dev_max)
-    return NULL;  /* Should never happen */
+	if (st_nbr_buffers >= st_template.dev_max)
+		return NULL;	/* Should never happen */
 
-  if (from_initialization)
-    priority = GFP_ATOMIC;
-  else
-    priority = GFP_KERNEL;
-
-  i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist);
-  tb = (ST_buffer *)scsi_init_malloc(i, priority);
-  if (tb) {
-    tb->this_size = i;
-    if (need_dma)
-      priority |= GFP_DMA;
-
-    /* Try to allocate the first segment up to ST_FIRST_ORDER and the
-       others big enough to reach the goal */
-    for (b_size = PAGE_SIZE << ST_FIRST_ORDER;
-	 b_size / 2 >= st_buffer_size && b_size > PAGE_SIZE; )
-	b_size /= 2;
-    for ( ; b_size >= PAGE_SIZE; b_size /= 2) {
-	tb->sg[0].address =
-	    (unsigned char *)scsi_init_malloc(b_size, priority);
-	if (tb->sg[0].address != NULL) {
-	    tb->sg[0].alt_address = NULL;
-	    tb->sg[0].length = b_size;
-	    break;
-	}
-    }
-    if (tb->sg[segs].address == NULL) {
-	scsi_init_free((char *)tb, tb->this_size);
-	tb = NULL;
-    }
-    else {  /* Got something, continue */
-
-	for (b_size = PAGE_SIZE;
-	     st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size; )
-	    b_size *= 2;
-
-	for (segs=1, got=tb->sg[0].length;
-	     got < st_buffer_size && segs < ST_FIRST_SG; ) {
-	    tb->sg[segs].address =
-		(unsigned char *)scsi_init_malloc(b_size, priority);
-	    if (tb->sg[segs].address == NULL) {
-		if (st_buffer_size - got <=
-		    (ST_FIRST_SG - segs) * b_size / 2) {
-		    b_size /= 2; /* Large enough for the rest of the buffers */
-		    continue;
-		}
-		for (i=0; i < segs - 1; i++)
-		    scsi_init_free(tb->sg[i].address, tb->sg[i].length);
-		scsi_init_free((char *)tb, tb->this_size);
-		tb = NULL;
-		break;
-	    }
-	    tb->sg[segs].alt_address = NULL;
-	    tb->sg[segs].length = b_size;
-	    got += b_size;
-	    segs++;
-	}
-    }
-  }
-  if (!tb) {
-    printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n",
-	   st_nbr_buffers);
-    return NULL;
-  }
-  tb->sg_segs = tb->orig_sg_segs = segs;
-  tb->b_data = tb->sg[0].address;
-
-#if DEBUG
-  if (debugging) {
-    printk(ST_DEB_MSG
-    "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
-	   st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
-    printk(ST_DEB_MSG
-	   "st: segment sizes: first %d, last %d bytes.\n",
-	   tb->sg[0].length, tb->sg[segs-1].length);
-  }
-#endif
-  tb->in_use = 0;
-  tb->dma = need_dma;
-  tb->buffer_size = got;
-  tb->writing = 0;
-  st_buffers[st_nbr_buffers++] = tb;
+	if (from_initialization)
+		priority = GFP_ATOMIC;
+	else
+		priority = GFP_KERNEL;
+
+	i = sizeof(ST_buffer) + (st_max_sg_segs - 1) * sizeof(struct scatterlist);
+	tb = (ST_buffer *) scsi_init_malloc(i, priority);
+	if (tb) {
+		tb->this_size = i;
+		if (need_dma)
+			priority |= GFP_DMA;
+
+		/* Try to allocate the first segment up to ST_FIRST_ORDER and the
+		   others big enough to reach the goal */
+		for (b_size = PAGE_SIZE << ST_FIRST_ORDER;
+		     b_size / 2 >= st_buffer_size && b_size > PAGE_SIZE;)
+			b_size /= 2;
+		for (; b_size >= PAGE_SIZE; b_size /= 2) {
+			tb->sg[0].address =
+			    (unsigned char *) scsi_init_malloc(b_size, priority);
+			if (tb->sg[0].address != NULL) {
+				tb->sg[0].alt_address = NULL;
+				tb->sg[0].length = b_size;
+				break;
+			}
+		}
+		if (tb->sg[segs].address == NULL) {
+			scsi_init_free((char *) tb, tb->this_size);
+			tb = NULL;
+		} else {	/* Got something, continue */
+
+			for (b_size = PAGE_SIZE;
+			     st_buffer_size > tb->sg[0].length + (ST_FIRST_SG - 1) * b_size;)
+				b_size *= 2;
+
+			for (segs = 1, got = tb->sg[0].length;
+			   got < st_buffer_size && segs < ST_FIRST_SG;) {
+				tb->sg[segs].address =
+				    (unsigned char *) scsi_init_malloc(b_size, priority);
+				if (tb->sg[segs].address == NULL) {
+					if (st_buffer_size - got <=
+					    (ST_FIRST_SG - segs) * b_size / 2) {
+						b_size /= 2;	/* Large enough for the rest of the buffers */
+						continue;
+					}
+					for (i = 0; i < segs - 1; i++)
+						scsi_init_free(tb->sg[i].address, tb->sg[i].length);
+					scsi_init_free((char *) tb, tb->this_size);
+					tb = NULL;
+					break;
+				}
+				tb->sg[segs].alt_address = NULL;
+				tb->sg[segs].length = b_size;
+				got += b_size;
+				segs++;
+			}
+		}
+	}
+	if (!tb) {
+		printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n",
+		       st_nbr_buffers);
+		return NULL;
+	}
+	tb->sg_segs = tb->orig_sg_segs = segs;
+	tb->b_data = tb->sg[0].address;
+
+#if DEBUG
+	if (debugging) {
+		printk(ST_DEB_MSG
+		       "st: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
+		 st_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
+		printk(ST_DEB_MSG
+		       "st: segment sizes: first %d, last %d bytes.\n",
+		       tb->sg[0].length, tb->sg[segs - 1].length);
+	}
+#endif
+	tb->in_use = 0;
+	tb->dma = need_dma;
+	tb->buffer_size = got;
+	tb->writing = 0;
+	st_buffers[st_nbr_buffers++] = tb;
 
-  return tb;
+	return tb;
 }
 
 
 /* Try to allocate a temporary enlarged tape buffer */
-	static int
-enlarge_buffer(ST_buffer *STbuffer, int new_size, int need_dma)
+static int enlarge_buffer(ST_buffer * STbuffer, int new_size, int need_dma)
 {
-  int segs, nbr, max_segs, b_size, priority, got;
+	int segs, nbr, max_segs, b_size, priority, got;
 
-  normalize_buffer(STbuffer);
+	normalize_buffer(STbuffer);
 
-  max_segs = STbuffer->use_sg;
-  if (max_segs > st_max_sg_segs)
-      max_segs = st_max_sg_segs;
-  nbr = max_segs - STbuffer->sg_segs;
-  if (nbr <= 0)
-      return FALSE;
-
-  priority = GFP_KERNEL;
-  if (need_dma)
-    priority |= GFP_DMA;
-  for (b_size = PAGE_SIZE; b_size * nbr < new_size - STbuffer->buffer_size; )
-      b_size *= 2;
-
-  for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size;
-       segs < max_segs && got < new_size; ) {
-      STbuffer->sg[segs].address =
-	  (unsigned char *)scsi_init_malloc(b_size, priority);
-      if (STbuffer->sg[segs].address == NULL) {
-	  if (new_size - got <= (max_segs - segs) * b_size / 2) {
-	      b_size /= 2;  /* Large enough for the rest of the buffers */
-	      continue;
-	  }
-	  printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n",
-		 new_size);
-	  normalize_buffer(STbuffer);
-	  return FALSE;
-      }
-      STbuffer->sg[segs].alt_address = NULL;
-      STbuffer->sg[segs].length = b_size;
-      STbuffer->sg_segs += 1;
-      got += b_size;
-      STbuffer->buffer_size = got;
-      segs++;
-  }
-#if DEBUG
-  if (debugging)
-      printk(ST_DEB_MSG
-	     "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n",
-	     got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size);
+	max_segs = STbuffer->use_sg;
+	if (max_segs > st_max_sg_segs)
+		max_segs = st_max_sg_segs;
+	nbr = max_segs - STbuffer->sg_segs;
+	if (nbr <= 0)
+		return FALSE;
+
+	priority = GFP_KERNEL;
+	if (need_dma)
+		priority |= GFP_DMA;
+	for (b_size = PAGE_SIZE; b_size * nbr < new_size - STbuffer->buffer_size;)
+		b_size *= 2;
+
+	for (segs = STbuffer->sg_segs, got = STbuffer->buffer_size;
+	     segs < max_segs && got < new_size;) {
+		STbuffer->sg[segs].address =
+		    (unsigned char *) scsi_init_malloc(b_size, priority);
+		if (STbuffer->sg[segs].address == NULL) {
+			if (new_size - got <= (max_segs - segs) * b_size / 2) {
+				b_size /= 2;	/* Large enough for the rest of the buffers */
+				continue;
+			}
+			printk(KERN_NOTICE "st: failed to enlarge buffer to %d bytes.\n",
+			       new_size);
+			normalize_buffer(STbuffer);
+			return FALSE;
+		}
+		STbuffer->sg[segs].alt_address = NULL;
+		STbuffer->sg[segs].length = b_size;
+		STbuffer->sg_segs += 1;
+		got += b_size;
+		STbuffer->buffer_size = got;
+		segs++;
+	}
+#if DEBUG
+	if (debugging)
+		printk(ST_DEB_MSG
+		       "st: Succeeded to enlarge buffer to %d bytes (segs %d->%d, %d).\n",
+		 got, STbuffer->orig_sg_segs, STbuffer->sg_segs, b_size);
 #endif
 
-  return TRUE;
+	return TRUE;
 }
 
 
 /* Release the extra buffer */
-	static void
-normalize_buffer(ST_buffer *STbuffer)
+static void normalize_buffer(ST_buffer * STbuffer)
 {
-  int i;
+	int i;
 
-  for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
-      scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length);
-      STbuffer->buffer_size -= STbuffer->sg[i].length;
-  }
+	for (i = STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
+		scsi_init_free(STbuffer->sg[i].address, STbuffer->sg[i].length);
+		STbuffer->buffer_size -= STbuffer->sg[i].length;
+	}
 #if DEBUG
-  if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
-      printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n",
-	     STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
+	if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
+		printk(ST_DEB_MSG "st: Buffer at %p normalized to %d bytes (segs %d).\n",
+		       STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
 #endif
-  STbuffer->sg_segs = STbuffer->orig_sg_segs;
+	STbuffer->sg_segs = STbuffer->orig_sg_segs;
 }
 
 
 /* Move data from the user buffer to the tape buffer. Returns zero (success) or
    negative error code. */
-	static int
-append_to_buffer(const char *ubp, ST_buffer *st_bp, int do_count)
+static int append_to_buffer(const char *ubp, ST_buffer * st_bp, int do_count)
 {
-    int i, cnt, res, offset;
+	int i, cnt, res, offset;
 
-    for (i=0, offset=st_bp->buffer_bytes;
-	 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-	offset -= st_bp->sg[i].length;
-    if (i == st_bp->sg_segs) {  /* Should never happen */
-	printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
-	return (-EIO);
-    }
-    for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
-	cnt = st_bp->sg[i].length - offset < do_count ?
-	    st_bp->sg[i].length - offset : do_count;
-	res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
-	if (res)
-	    return (-EFAULT);
-	do_count -= cnt;
-	st_bp->buffer_bytes += cnt;
-	ubp += cnt;
-	offset = 0;
-    }
-    if (do_count) {  /* Should never happen */
-	printk(KERN_WARNING "st: append_to_buffer overflow (left %d).\n",
-	       do_count);
-	return (-EIO);
-    }
-    return 0;
+	for (i = 0, offset = st_bp->buffer_bytes;
+	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+		offset -= st_bp->sg[i].length;
+	if (i == st_bp->sg_segs) {	/* Should never happen */
+		printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for (; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length - offset < do_count ?
+		    st_bp->sg[i].length - offset : do_count;
+		res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
+		if (res)
+			return (-EFAULT);
+		do_count -= cnt;
+		st_bp->buffer_bytes += cnt;
+		ubp += cnt;
+		offset = 0;
+	}
+	if (do_count) {		/* Should never happen */
+		printk(KERN_WARNING "st: append_to_buffer overflow (left %d).\n",
+		       do_count);
+		return (-EIO);
+	}
+	return 0;
 }
 
 
 /* Move data from the tape buffer to the user buffer. Returns zero (success) or
    negative error code. */
-	static int
-from_buffer(ST_buffer *st_bp, char *ubp, int do_count)
+static int from_buffer(ST_buffer * st_bp, char *ubp, int do_count)
 {
-    int i, cnt, res, offset;
+	int i, cnt, res, offset;
 
-    for (i=0, offset=st_bp->read_pointer;
-	 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
-	offset -= st_bp->sg[i].length;
-    if (i == st_bp->sg_segs) {  /* Should never happen */
-	printk(KERN_WARNING "st: from_buffer offset overflow.\n");
-	return (-EIO);
-    }
-    for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
-	cnt = st_bp->sg[i].length - offset < do_count ?
-	    st_bp->sg[i].length - offset : do_count;
-	res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
-	if (res)
-	    return (-EFAULT);
-	do_count -= cnt;
-	st_bp->buffer_bytes -= cnt;
-	st_bp->read_pointer += cnt;
-	ubp += cnt;
-	offset = 0;
-    }
-    if (do_count) {  /* Should never happen */
-	printk(KERN_WARNING "st: from_buffer overflow (left %d).\n",
-	       do_count);
-	return (-EIO);
-    }
-    return 0;
+	for (i = 0, offset = st_bp->read_pointer;
+	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+		offset -= st_bp->sg[i].length;
+	if (i == st_bp->sg_segs) {	/* Should never happen */
+		printk(KERN_WARNING "st: from_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for (; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length - offset < do_count ?
+		    st_bp->sg[i].length - offset : do_count;
+		res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
+		if (res)
+			return (-EFAULT);
+		do_count -= cnt;
+		st_bp->buffer_bytes -= cnt;
+		st_bp->read_pointer += cnt;
+		ubp += cnt;
+		offset = 0;
+	}
+	if (do_count) {		/* Should never happen */
+		printk(KERN_WARNING "st: from_buffer overflow (left %d).\n",
+		       do_count);
+		return (-EIO);
+	}
+	return 0;
 }
 
 
 /* Validate the options from command line or module parameters */
 static void validate_options(void)
 {
-    if (buffer_kbs > 0)
-	st_buffer_size = buffer_kbs * ST_KILOBYTE;
-    if (write_threshold_kbs > 0)
-	st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
-    else if (buffer_kbs > 0)
-	st_write_threshold = st_buffer_size - 2048;
-    if (st_write_threshold > st_buffer_size) {
-	st_write_threshold = st_buffer_size;
-	printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n",
-	       st_write_threshold);
-    }
-    if (max_buffers >= 0)
-	st_max_buffers = max_buffers;
-    if (max_sg_segs >= ST_FIRST_SG)
-	st_max_sg_segs = max_sg_segs;
+	if (buffer_kbs > 0)
+		st_buffer_size = buffer_kbs * ST_KILOBYTE;
+	if (write_threshold_kbs > 0)
+		st_write_threshold = write_threshold_kbs * ST_KILOBYTE;
+	else if (buffer_kbs > 0)
+		st_write_threshold = st_buffer_size - 2048;
+	if (st_write_threshold > st_buffer_size) {
+		st_write_threshold = st_buffer_size;
+		printk(KERN_WARNING "st: write_threshold limited to %d bytes.\n",
+		       st_write_threshold);
+	}
+	if (max_buffers >= 0)
+		st_max_buffers = max_buffers;
+	if (max_sg_segs >= ST_FIRST_SG)
+		st_max_sg_segs = max_sg_segs;
 }
 
 #ifndef MODULE
 /* Set the boot options. Syntax is defined in README.st.
-*/
+ */
 static int __init st_setup(char *str)
 {
-    int i, len, ints[5];
-    char *stp;
+	int i, len, ints[5];
+	char *stp;
 
-    stp = get_options(str, ARRAY_SIZE(ints), ints);
+	stp = get_options(str, ARRAY_SIZE(ints), ints);
 
-    if (ints[0] > 0) {
-	for (i=0; i < ints[0] && i < ARRAY_SIZE(parms) ; i++)
-	    *parms[i].val = ints[i + 1];
-    }
-    else {
-	while (stp != NULL) {
-	    for (i=0; i < ARRAY_SIZE(parms); i++) {
-		len = strlen(parms[i].name);
-		if (!strncmp(stp, parms[i].name, len) &&
-		    (*(stp + len) == ':' || *(stp + len) == '=')) {
-		    *parms[i].val = simple_strtoul(stp + len + 1, NULL, 0);
-		    break;
-		}
-	    }
-	    if (i >= sizeof(parms) / sizeof(struct st_dev_parm))
-		printk(KERN_WARNING "st: illegal parameter in '%s'\n",
-		       stp);
-	    stp = strchr(stp, ',');
-	    if (stp)
-		stp++;
+	if (ints[0] > 0) {
+		for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
+			*parms[i].val = ints[i + 1];
+	} else {
+		while (stp != NULL) {
+			for (i = 0; i < ARRAY_SIZE(parms); i++) {
+				len = strlen(parms[i].name);
+				if (!strncmp(stp, parms[i].name, len) &&
+				    (*(stp + len) == ':' || *(stp + len) == '=')) {
+					*parms[i].val = simple_strtoul(stp + len + 1, NULL, 0);
+					break;
+				}
+			}
+			if (i >= sizeof(parms) / sizeof(struct st_dev_parm))
+				 printk(KERN_WARNING "st: illegal parameter in '%s'\n",
+					stp);
+			stp = strchr(stp, ',');
+			if (stp)
+				stp++;
+		}
 	}
-    }
 
-    validate_options();
+	validate_options();
 
-    return 1;
+	return 1;
 }
 
 __setup("st=", st_setup);
@@ -3393,108 +3267,112 @@
 #endif
 
 
-static struct file_operations st_fops = {
-   NULL,            /* lseek - default */
-   st_read,         /* read - general block-dev read */
-   st_write,        /* write - general block-dev write */
-   NULL,            /* readdir - bad */
-   NULL,            /* select */
-   st_ioctl,        /* ioctl */
-   NULL,            /* mmap */
-   scsi_tape_open,  /* open */
-   scsi_tape_flush, /* flush */
-   scsi_tape_close, /* release */
-   NULL		    /* fsync */
+static struct file_operations st_fops =
+{
+	NULL,			/* lseek - default */
+	st_read,		/* read - general block-dev read */
+	st_write,		/* write - general block-dev write */
+	NULL,			/* readdir - bad */
+	NULL,			/* select */
+	st_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	scsi_tape_open,		/* open */
+	scsi_tape_flush,	/* flush */
+	scsi_tape_close,	/* release */
+	NULL			/* fsync */
 };
 
-static int st_attach(Scsi_Device * SDp){
-   Scsi_Tape * tpnt;
-   ST_mode * STm;
-   ST_partstat * STps;
-   int i;
-
-   if (SDp->type != TYPE_TAPE)
-       return 1;
-
-   if (st_template.nr_dev >= st_template.dev_max) {
-       SDp->attached--;
-       return 1;
-   }
-
-   for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
-     if(!tpnt->device) break;
-
-   if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)");
-
-   scsi_tapes[i].device = SDp;
-   if (SDp->scsi_level <= 2)
-     scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
-   else
-     scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
-
-   tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
-   tpnt->dirty = 0;
-   tpnt->in_use = 0;
-   tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
-   tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
-   tpnt->density = 0;
-   tpnt->do_auto_lock = ST_AUTO_LOCK;
-   tpnt->can_bsr = ST_IN_FILE_POS;
-   tpnt->can_partitions = 0;
-   tpnt->two_fm = ST_TWO_FM;
-   tpnt->fast_mteom = ST_FAST_MTEOM;
-   tpnt->scsi2_logical = ST_SCSI2LOGICAL;
-   tpnt->write_threshold = st_write_threshold;
-   tpnt->default_drvbuffer = 0xff; /* No forced buffering */
-   tpnt->partition = 0;
-   tpnt->new_partition = 0;
-   tpnt->nbr_partitions = 0;
-   tpnt->timeout = ST_TIMEOUT;
-   tpnt->long_timeout = ST_LONG_TIMEOUT;
-
-   for (i=0; i < ST_NBR_MODES; i++) {
-     STm = &(tpnt->modes[i]);
-     STm->defined = FALSE;
-     STm->sysv = ST_SYSV;
-     STm->defaults_for_writes = 0;
-     STm->do_async_writes = ST_ASYNC_WRITES;
-     STm->do_buffer_writes = ST_BUFFER_WRITES;
-     STm->do_read_ahead = ST_READ_AHEAD;
-     STm->default_compression = ST_DONT_TOUCH;
-     STm->default_blksize = (-1);  /* No forced size */
-     STm->default_density = (-1);  /* No forced density */
-   }
-
-   for (i=0; i < ST_NBR_PARTITIONS; i++) {
-     STps = &(tpnt->ps[i]);
-     STps->rw = ST_IDLE;
-     STps->eof = ST_NOEOF;
-     STps->at_sm = 0;
-     STps->last_block_valid = FALSE;
-     STps->drv_block = (-1);
-     STps->drv_file = (-1);
-   }
+static int st_attach(Scsi_Device * SDp)
+{
+	Scsi_Tape *tpnt;
+	ST_mode *STm;
+	ST_partstat *STps;
+	int i;
+
+	if (SDp->type != TYPE_TAPE)
+		return 1;
+
+	if (st_template.nr_dev >= st_template.dev_max) {
+		SDp->attached--;
+		return 1;
+	}
+	for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
+		if (!tpnt->device)
+			break;
+
+	if (i >= st_template.dev_max)
+		panic("scsi_devices corrupt (st)");
+
+	scsi_tapes[i].device = SDp;
+	if (SDp->scsi_level <= 2)
+		scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
+	else
+		scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
+
+	tpnt->devt = MKDEV(SCSI_TAPE_MAJOR, i);
+	tpnt->dirty = 0;
+	tpnt->in_use = 0;
+	tpnt->drv_buffer = 1;	/* Try buffering if no mode sense */
+	tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
+	tpnt->density = 0;
+	tpnt->do_auto_lock = ST_AUTO_LOCK;
+	tpnt->can_bsr = ST_IN_FILE_POS;
+	tpnt->can_partitions = 0;
+	tpnt->two_fm = ST_TWO_FM;
+	tpnt->fast_mteom = ST_FAST_MTEOM;
+	tpnt->scsi2_logical = ST_SCSI2LOGICAL;
+	tpnt->write_threshold = st_write_threshold;
+	tpnt->default_drvbuffer = 0xff;		/* No forced buffering */
+	tpnt->partition = 0;
+	tpnt->new_partition = 0;
+	tpnt->nbr_partitions = 0;
+	tpnt->timeout = ST_TIMEOUT;
+	tpnt->long_timeout = ST_LONG_TIMEOUT;
+
+	for (i = 0; i < ST_NBR_MODES; i++) {
+		STm = &(tpnt->modes[i]);
+		STm->defined = FALSE;
+		STm->sysv = ST_SYSV;
+		STm->defaults_for_writes = 0;
+		STm->do_async_writes = ST_ASYNC_WRITES;
+		STm->do_buffer_writes = ST_BUFFER_WRITES;
+		STm->do_read_ahead = ST_READ_AHEAD;
+		STm->default_compression = ST_DONT_TOUCH;
+		STm->default_blksize = (-1);	/* No forced size */
+		STm->default_density = (-1);	/* No forced density */
+	}
 
-   tpnt->current_mode = 0;
-   tpnt->modes[0].defined = TRUE;
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(tpnt->ps[i]);
+		STps->rw = ST_IDLE;
+		STps->eof = ST_NOEOF;
+		STps->at_sm = 0;
+		STps->last_block_valid = FALSE;
+		STps->drv_block = (-1);
+		STps->drv_file = (-1);
+	}
 
-   tpnt->density_changed = tpnt->compression_changed =
-     tpnt->blksize_changed = FALSE;
+	tpnt->current_mode = 0;
+	tpnt->modes[0].defined = TRUE;
 
-   st_template.nr_dev++;
-   return 0;
+	tpnt->density_changed = tpnt->compression_changed =
+	    tpnt->blksize_changed = FALSE;
+
+	st_template.nr_dev++;
+	return 0;
 };
 
 static int st_detect(Scsi_Device * SDp)
 {
-  if(SDp->type != TYPE_TAPE) return 0;
+	if (SDp->type != TYPE_TAPE)
+		return 0;
 
-  printk(KERN_WARNING
-	 "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
-	 st_template.dev_noticed++,
-	 SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+	printk(KERN_WARNING
+	"Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
+	       st_template.dev_noticed++,
+	       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
 
-  return 1;
+	return 1;
 }
 
 static int st_registered = 0;
@@ -3502,142 +3380,142 @@
 /* Driver initialization (not __init because may be called later) */
 static int st_init()
 {
-  int i;
-  Scsi_Tape * STp;
-  int target_nbr;
-
-  if (st_template.dev_noticed == 0) return 0;
-
-  printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n",
-	 st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
-
-  if(!st_registered) {
-    if (register_chrdev(SCSI_TAPE_MAJOR,"st",&st_fops)) {
-      printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",MAJOR_NR);
-      return 1;
-    }
-    st_registered++;
-  }
-
-  if (scsi_tapes) return 0;
-  st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
-  if (st_template.dev_max < ST_MAX_TAPES)
-    st_template.dev_max = ST_MAX_TAPES;
-  if (st_template.dev_max > 128 / ST_NBR_MODES)
-    printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
-  scsi_tapes =
-    (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape),
-				   GFP_ATOMIC);
-  if (scsi_tapes == NULL) {
-    printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
-    unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-    return 1;
-  }
-
-#if DEBUG
-  printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
-	 st_buffer_size, st_write_threshold);
-#endif
-
-  memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape));
-  for (i=0; i < st_template.dev_max; ++i) {
-    STp = &(scsi_tapes[i]);
-    STp->capacity = 0xfffff;
-    STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget),
-						       GFP_ATOMIC);
-    /* Initialize status */
-    memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
-  }
-
-  /* Allocate the buffers */
-  st_buffers =
-    (ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *),
-				    GFP_ATOMIC);
-  if (st_buffers == NULL) {
-    printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
-    unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-    scsi_init_free((char *) scsi_tapes,
-		   st_template.dev_max * sizeof(Scsi_Tape));
-    return 1;
-  }
-
-  target_nbr = st_template.dev_noticed;
-  if (target_nbr < ST_EXTRA_DEVS)
-    target_nbr = ST_EXTRA_DEVS;
-  if (target_nbr > st_max_buffers)
-    target_nbr = st_max_buffers;
-
-  for (i=st_nbr_buffers=0; i < target_nbr; i++) {
-    if (!new_tape_buffer(TRUE, TRUE)) {
-      if (i == 0) {
-	printk(KERN_INFO "No tape buffers allocated at initialization.\n");
-	break;
-      }
-      printk(KERN_INFO "Number of tape buffers adjusted.\n");
-      break;
-    }
-  }
+	int i;
+	Scsi_Tape *STp;
+	int target_nbr;
+
+	if (st_template.dev_noticed == 0)
+		return 0;
+
+	printk(KERN_INFO "st: bufsize %d, wrt %d, max init. buffers %d, s/g segs %d.\n",
+	       st_buffer_size, st_write_threshold, st_max_buffers, st_max_sg_segs);
+
+	if (!st_registered) {
+		if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops)) {
+			printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
+			return 1;
+		}
+		st_registered++;
+	}
+	if (scsi_tapes)
+		return 0;
+	st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
+	if (st_template.dev_max < ST_MAX_TAPES)
+		st_template.dev_max = ST_MAX_TAPES;
+	if (st_template.dev_max > 128 / ST_NBR_MODES)
+		printk(KERN_INFO "st: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
+	scsi_tapes =
+	    (Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape),
+					   GFP_ATOMIC);
+	if (scsi_tapes == NULL) {
+		printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
+		unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+		return 1;
+	}
+#if DEBUG
+	printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
+	       st_buffer_size, st_write_threshold);
+#endif
+
+	memset(scsi_tapes, 0, st_template.dev_max * sizeof(Scsi_Tape));
+	for (i = 0; i < st_template.dev_max; ++i) {
+		STp = &(scsi_tapes[i]);
+		STp->capacity = 0xfffff;
+		STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget),
+							     GFP_ATOMIC);
+		/* Initialize status */
+		memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
+	}
 
-  return 0;
+	/* Allocate the buffers */
+	st_buffers =
+	    (ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *),
+					    GFP_ATOMIC);
+	if (st_buffers == NULL) {
+		printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
+		unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+		scsi_init_free((char *) scsi_tapes,
+			       st_template.dev_max * sizeof(Scsi_Tape));
+		return 1;
+	}
+	target_nbr = st_template.dev_noticed;
+	if (target_nbr < ST_EXTRA_DEVS)
+		target_nbr = ST_EXTRA_DEVS;
+	if (target_nbr > st_max_buffers)
+		target_nbr = st_max_buffers;
+
+	for (i = st_nbr_buffers = 0; i < target_nbr; i++) {
+		if (!new_tape_buffer(TRUE, TRUE)) {
+			if (i == 0) {
+				printk(KERN_INFO "No tape buffers allocated at initialization.\n");
+				break;
+			}
+			printk(KERN_INFO "Number of tape buffers adjusted.\n");
+			break;
+		}
+	}
+
+	return 0;
 }
 
 static void st_detach(Scsi_Device * SDp)
 {
-  Scsi_Tape * tpnt;
-  int i;
+	Scsi_Tape *tpnt;
+	int i;
 
-  for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
-    if(tpnt->device == SDp) {
-      tpnt->device = NULL;
-      SDp->attached--;
-      st_template.nr_dev--;
-      st_template.dev_noticed--;
-      return;
-    }
-  return;
+	for (tpnt = scsi_tapes, i = 0; i < st_template.dev_max; i++, tpnt++)
+		if (tpnt->device == SDp) {
+			tpnt->device = NULL;
+			SDp->attached--;
+			st_template.nr_dev--;
+			st_template.dev_noticed--;
+			return;
+		}
+	return;
 }
 
 
 #ifdef MODULE
 
-int __init init_module(void) {
-  int result;
+int __init init_module(void)
+{
+	int result;
 
-  validate_options();
+	validate_options();
 
-  st_template.module = &__this_module;
-  result = scsi_register_module(MODULE_SCSI_DEV, &st_template);
-  if (result)
-      return result;
+	st_template.module = &__this_module;
+	result = scsi_register_module(MODULE_SCSI_DEV, &st_template);
+	if (result)
+		return result;
 
-  return 0;
+	return 0;
 }
 
-void cleanup_module( void)
+void cleanup_module(void)
 {
-  int i, j;
+	int i, j;
 
-  scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
-  unregister_chrdev(SCSI_TAPE_MAJOR, "st");
-  st_registered--;
-  if(scsi_tapes != NULL) {
-    scsi_init_free((char *) scsi_tapes,
-		   st_template.dev_max * sizeof(Scsi_Tape));
-
-    if (st_buffers != NULL) {
-      for (i=0; i < st_nbr_buffers; i++)
-	if (st_buffers[i] != NULL) {
-	  for (j=0; j < st_buffers[i]->sg_segs; j++)
-	      scsi_init_free((char *) st_buffers[i]->sg[j].address,
-			     st_buffers[i]->sg[j].length);
-	  scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size);
+	scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
+	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
+	st_registered--;
+	if (scsi_tapes != NULL) {
+		scsi_init_free((char *) scsi_tapes,
+			       st_template.dev_max * sizeof(Scsi_Tape));
+
+		if (st_buffers != NULL) {
+			for (i = 0; i < st_nbr_buffers; i++)
+			{
+				if (st_buffers[i] != NULL) {
+					for (j = 0; j < st_buffers[i]->sg_segs; j++)
+						scsi_init_free((char *) st_buffers[i]->sg[j].address,
+							       st_buffers[i]->sg[j].length);
+					scsi_init_free((char *) st_buffers[i], st_buffers[i]->this_size);
+				}
+			}	
+			scsi_init_free((char *) st_buffers, st_template.dev_max * sizeof(ST_buffer *));
+		}
 	}
-
-      scsi_init_free((char *) st_buffers,
-		     st_template.dev_max * sizeof(ST_buffer *));
-    }
-  }
-  st_template.dev_max = 0;
-  printk(KERN_INFO "st: Unloaded.\n");
+	st_template.dev_max = 0;
+	printk(KERN_INFO "st: Unloaded.\n");
 }
-#endif /* MODULE */
+#endif				/* MODULE */
diff -u --recursive --new-file v2.3.16/linux/drivers/scsi/st.h linux/drivers/scsi/st.h
--- v2.3.16/linux/drivers/scsi/st.h	Sat May 22 14:50:07 1999
+++ linux/drivers/scsi/st.h	Sat Sep  4 10:48:46 1999
@@ -1,9 +1,9 @@
 
 #ifndef _ST_H
-	#define _ST_H
+#define _ST_H
 /*
-	$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $
-*/
+   $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $
+ */
 
 #ifndef _SCSI_H
 #include "scsi.h"
@@ -11,36 +11,36 @@
 
 /* The tape buffer descriptor. */
 typedef struct {
-  unsigned char in_use;
-  unsigned char dma;	/* DMA-able buffer */
-  int this_size;        /* allocated size of the structure */
-  int buffer_size;
-  int buffer_blocks;
-  int buffer_bytes;
-  int read_pointer;
-  int writing;
-  int last_result;
-  int last_result_fatal;
-  Scsi_Cmnd *last_SCpnt;
-  unsigned char *b_data;
-  unsigned short   use_sg;     /* zero or number of segments for this adapter */
-  unsigned short sg_segs;      /* total number of allocated segments */
-  unsigned short orig_sg_segs; /* number of segments allocated at first try */
-  struct scatterlist sg[1];    /* MUST BE last item */
+	unsigned char in_use;
+	unsigned char dma;	/* DMA-able buffer */
+	int this_size;		/* allocated size of the structure */
+	int buffer_size;
+	int buffer_blocks;
+	int buffer_bytes;
+	int read_pointer;
+	int writing;
+	int last_result;
+	int last_result_fatal;
+	Scsi_Cmnd *last_SCpnt;
+	unsigned char *b_data;
+	unsigned short use_sg;	/* zero or number of segments for this adapter */
+	unsigned short sg_segs;	/* total number of allocated segments */
+	unsigned short orig_sg_segs;	/* number of segments allocated at first try */
+	struct scatterlist sg[1];	/* MUST BE last item */
 } ST_buffer;
 
 
 /* The tape mode definition */
 typedef struct {
-  unsigned char defined;
-  unsigned char sysv;   /* SYS V semantics? */
-  unsigned char do_async_writes;
-  unsigned char do_buffer_writes;
-  unsigned char do_read_ahead;
-  unsigned char defaults_for_writes;
-  unsigned char default_compression; /* 0 = don't touch, etc */
-  short default_density; /* Forced density, -1 = no value */
-  int default_blksize;	/* Forced blocksize, -1 = no value */
+	unsigned char defined;
+	unsigned char sysv;	/* SYS V semantics? */
+	unsigned char do_async_writes;
+	unsigned char do_buffer_writes;
+	unsigned char do_read_ahead;
+	unsigned char defaults_for_writes;
+	unsigned char default_compression;	/* 0 = don't touch, etc */
+	short default_density;	/* Forced density, -1 = no value */
+	int default_blksize;	/* Forced blocksize, -1 = no value */
 } ST_mode;
 
 #define ST_NBR_MODE_BITS 2
@@ -50,76 +50,76 @@
 
 /* The status related to each partition */
 typedef struct {
-  unsigned char rw;
-  unsigned char eof;
-  unsigned char at_sm;
-  unsigned char last_block_valid;
-  u32 last_block_visited;
-  int drv_block;	/* The block where the drive head is */
-  int drv_file;
+	unsigned char rw;
+	unsigned char eof;
+	unsigned char at_sm;
+	unsigned char last_block_valid;
+	u32 last_block_visited;
+	int drv_block;		/* The block where the drive head is */
+	int drv_file;
 } ST_partstat;
 
 #define ST_NBR_PARTITIONS 4
 
 /* The tape drive descriptor */
 typedef struct {
-  kdev_t devt;
-  unsigned capacity;
-  Scsi_Device* device;
-  struct semaphore sem;
-  ST_buffer * buffer;
-
-  /* Drive characteristics */
-  unsigned char omit_blklims;
-  unsigned char do_auto_lock;
-  unsigned char can_bsr;
-  unsigned char can_partitions;
-  unsigned char two_fm;
-  unsigned char fast_mteom;
-  unsigned char restr_dma;
-  unsigned char scsi2_logical;
-  unsigned char default_drvbuffer;  /* 0xff = don't touch, value 3 bits */
-  int write_threshold;
-  int timeout;			/* timeout for normal commands */
-  int long_timeout;		/* timeout for commands known to take long time*/
-
-  /* Mode characteristics */
-  ST_mode modes[ST_NBR_MODES];
-  int current_mode;
-
-  /* Status variables */
-  int partition;
-  int new_partition;
-  int nbr_partitions;    /* zero until partition support enabled */
-  ST_partstat ps[ST_NBR_PARTITIONS];
-  unsigned char dirty;
-  unsigned char ready;
-  unsigned char write_prot;
-  unsigned char drv_write_prot;
-  unsigned char in_use;
-  unsigned char blksize_changed;
-  unsigned char density_changed;
-  unsigned char compression_changed;
-  unsigned char drv_buffer;
-  unsigned char density;
-  unsigned char door_locked;
-  unsigned char rew_at_close;
-  int block_size;
-  int min_block;
-  int max_block;
-  int recover_count;
-  struct mtget * mt_status;
+	kdev_t devt;
+	unsigned capacity;
+	Scsi_Device *device;
+	struct semaphore sem;
+	ST_buffer *buffer;
+
+	/* Drive characteristics */
+	unsigned char omit_blklims;
+	unsigned char do_auto_lock;
+	unsigned char can_bsr;
+	unsigned char can_partitions;
+	unsigned char two_fm;
+	unsigned char fast_mteom;
+	unsigned char restr_dma;
+	unsigned char scsi2_logical;
+	unsigned char default_drvbuffer;	/* 0xff = don't touch, value 3 bits */
+	int write_threshold;
+	int timeout;		/* timeout for normal commands */
+	int long_timeout;	/* timeout for commands known to take long time */
+
+	/* Mode characteristics */
+	ST_mode modes[ST_NBR_MODES];
+	int current_mode;
+
+	/* Status variables */
+	int partition;
+	int new_partition;
+	int nbr_partitions;	/* zero until partition support enabled */
+	ST_partstat ps[ST_NBR_PARTITIONS];
+	unsigned char dirty;
+	unsigned char ready;
+	unsigned char write_prot;
+	unsigned char drv_write_prot;
+	unsigned char in_use;
+	unsigned char blksize_changed;
+	unsigned char density_changed;
+	unsigned char compression_changed;
+	unsigned char drv_buffer;
+	unsigned char density;
+	unsigned char door_locked;
+	unsigned char rew_at_close;
+	int block_size;
+	int min_block;
+	int max_block;
+	int recover_count;
+	struct mtget *mt_status;
 
 #if DEBUG
-  unsigned char write_pending;
-  int nbr_finished;
-  int nbr_waits;
-  unsigned char last_cmnd[6];
-  unsigned char last_sense[16];
+	unsigned char write_pending;
+	int nbr_finished;
+	int nbr_waits;
+	unsigned char last_cmnd[6];
+	unsigned char last_sense[16];
 #endif
 } Scsi_Tape;
 
-extern Scsi_Tape * scsi_tapes;
+extern Scsi_Tape *scsi_tapes;
 
 /* Values of eof */
 #define	ST_NOEOF	0
@@ -159,4 +159,3 @@
 #define ST_YES         2
 
 #endif
-
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.3.16/linux/drivers/sound/Config.in	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sound/Config.in	Tue Sep  7 10:22:12 1999
@@ -10,9 +10,16 @@
 # Prompt user for primary drivers.
 
 dep_tristate 'C-Media PCI (CMI8338/8378)' CONFIG_SOUND_CMPCI $CONFIG_SOUND
+if [ "$CONFIG_SOUND_CMPCI" = "y" -o "$CONFIG_SOUND_CMPCI" = "m" ]; then
+   bool 'Enable legacy FM' CONFIG_SOUND_CMPCI_FM
+   bool 'Enable legacy MPU-401' CONFIG_SOUND_CMPCI_MIDI
+fi
 dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
 dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND
 dep_tristate 'ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    dep_tristate 'ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+fi
 dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
 if [ "$CONFIG_VISWS" = "y" ]; then
     dep_tristate 'SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
@@ -171,6 +178,8 @@
       fi
   fi
   
+  dep_tristate 'VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_SOUND_OSS
+
   dep_tristate 'Support for OPTi MAD16 and/or Mozart based cards' CONFIG_SOUND_MAD16 $CONFIG_SOUND_OSS
   if [ "$CONFIG_SOUND_MAD16" = "y" -o "$CONFIG_SOUND_MAD16" = "m" ]; then
     bool 'Support MIDI in older MAD16 based cards (requires SB)' CONFIG_MAD16_OLDCARD
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/Makefile linux/drivers/sound/Makefile
--- v2.3.16/linux/drivers/sound/Makefile	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sound/Makefile	Tue Sep  7 10:22:12 1999
@@ -53,6 +53,7 @@
 obj-$(CONFIG_SOUND_CS4232)	+= uart401.o
 obj-$(CONFIG_SOUND_GUS)		+= gus.o ad1848.o
 obj-$(CONFIG_SOUND_MAD16)	+= mad16.o ad1848.o sb.o uart401.o
+obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx.o sb.o uart401.o
 obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
 obj-$(CONFIG_SOUND_MPU401)	+= mpu401.o
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/cmpci.c linux/drivers/sound/cmpci.c
--- v2.3.16/linux/drivers/sound/cmpci.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sound/cmpci.c	Tue Sep  7 10:22:12 1999
@@ -2311,7 +2311,9 @@
 		index++;
 		continue;
 
+	err_dev4:
 		unregister_sound_midi(s->dev_midi);
+	err_dev3:
 		unregister_sound_mixer(s->dev_mixer);
 	err_dev2:
 		unregister_sound_dsp(s->dev_audio);
@@ -2326,6 +2328,7 @@
 #ifdef CONFIG_SOUND_CMPCI_MIDI
 		release_region(s->iomidi, CM_EXTENT_MIDI);
 #endif
+	err_region4:
 		release_region(s->iobase, CM_EXTENT_CODEC);
 	err_region5:
 		kfree_s(s, sizeof(struct cm_state));
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- v2.3.16/linux/drivers/sound/dmasound.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sound/dmasound.c	Sat Sep  4 13:09:36 1999
@@ -5646,7 +5646,9 @@
 		sound.mach.irqcleanup();
 	}
 
+#ifdef CONFIG_PPC
 	sq_release_read_buffers();
+#endif
 	sq_release_buffers();
 
 	if (mixer_unit >= 0)
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.3.16/linux/drivers/sound/es1370.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sound/es1370.c	Tue Sep  7 10:19:45 1999
@@ -108,6 +108,11 @@
  *                     removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
  *    12.08.99   0.27  module_init/__setup fixes
  *    19.08.99   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
+ *    31.08.99   0.29  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.30  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -1059,7 +1064,7 @@
 	
 	if (s->dma_dac1.mapped || !s->dma_dac1.ready)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac1.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1071,7 +1076,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac1.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
@@ -1081,7 +1086,7 @@
 			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1095,7 +1100,7 @@
 
 	if (s->dma_dac2.mapped || !s->dma_dac2.ready)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac2.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1107,7 +1112,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac2.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
@@ -1117,7 +1122,7 @@
 			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -2071,6 +2076,7 @@
 static ssize_t es1370_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2081,7 +2087,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -2092,15 +2101,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -2109,13 +2128,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	__set_current_state(TASK_RUNNING);
+        remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t es1370_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1370_state *s = (struct es1370_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2126,7 +2149,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -2139,15 +2165,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -2160,6 +2196,8 @@
 		es1370_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	__set_current_state(TASK_RUNNING);
+        remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2246,7 +2284,7 @@
 	VALIDATE_STATE(s);
 
 	if (file->f_mode & FMODE_WRITE) {
-		current->state = TASK_INTERRUPTIBLE;
+		__set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&s->midi.owait, &wait);
 		for (;;) {
 			spin_lock_irqsave(&s->lock, flags);
@@ -2258,7 +2296,7 @@
 				break;
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2266,7 +2304,7 @@
 				DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");)
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
 	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2337,6 +2375,11 @@
 	{ SOUND_MIXER_WRITE_OGAIN, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+				 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_es1370(void)
 {
 	struct es1370_state *s;
@@ -2346,11 +2389,10 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.28 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.29 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
-		if (pcidev->resource[0].flags == 0 || 
-		    (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (!RSRCISIOREGION(pcidev, 0))
 			continue;
 		if (pcidev->irq == 0) 
 			continue;
@@ -2366,8 +2408,9 @@
 		init_waitqueue_head(&s->midi.iwait);
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
+		spin_lock_init(&s->lock);
 		s->magic = ES1370_MAGIC;
-		s->io = pcidev->resource[0].start;
+		s->io = RSRCADDRESS(pcidev, 0);
 		s->irq = pcidev->irq;
 		if (check_region(s->io, ES1370_EXTENT)) {
 			printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
@@ -2485,11 +2528,12 @@
 
 static int __init es1370_setup(char *str)
 {
-	static unsigned __initdata nr_dev = 0;
+	static unsigned __initlocaldata nr_dev = 0;
 
 	if (nr_dev >= NR_DEVICE)
 		return 0;
 
+	(void)
 	(   (get_option(&str,&joystick[nr_dev]) == 2)
 	 && (get_option(&str,&lineout [nr_dev]) == 2)
 	 &&  get_option(&str,&micbias [nr_dev])
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.3.16/linux/drivers/sound/es1371.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/sound/es1371.c	Tue Sep  7 10:19:45 1999
@@ -81,6 +81,11 @@
  *                     added a /proc file system for dumping hardware state
  *                     updated SRC and CODEC w/r functions to accomodate bugs
  *                     in some versions of the ES137x chips.
+ *    31.08.99   0.17  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.18  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  */
 
@@ -1608,8 +1613,8 @@
 	if (s->dma_dac1.mapped || !s->dma_dac1.ready)
 		return 0;
 
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac1.wait, &wait);
-        current->state = TASK_INTERRUPTIBLE;
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
 		count = s->dma_dac1.count;
@@ -1620,7 +1625,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac1.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2 / s->dac1rate;
@@ -1629,7 +1634,7 @@
 			printk(KERN_DEBUG "es1371: dac1 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac1.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1644,8 +1649,8 @@
 	if (s->dma_dac2.mapped || !s->dma_dac2.ready)
 		return 0;
 
+        __set_current_state(TASK_UNINTERRUPTIBLE);
         add_wait_queue(&s->dma_dac2.wait, &wait);
-        current->state = TASK_UNINTERRUPTIBLE;
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
 		count = s->dma_dac2.count;
@@ -1656,7 +1661,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac2.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2 / s->dac2rate;
@@ -1665,7 +1670,7 @@
 			printk(KERN_DEBUG "es1371: dac2 dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac2.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -2607,6 +2612,7 @@
 static ssize_t es1371_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2617,7 +2623,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -2628,15 +2637,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -2645,13 +2664,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t es1371_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct es1371_state *s = (struct es1371_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -2662,7 +2685,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -2675,15 +2701,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -2696,6 +2732,8 @@
 		es1371_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2781,7 +2819,7 @@
 
 	VALIDATE_STATE(s);
 	if (file->f_mode & FMODE_WRITE) {
-		current->state = TASK_INTERRUPTIBLE;
+		__set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&s->midi.owait, &wait);
 		for (;;) {
 			spin_lock_irqsave(&s->lock, flags);
@@ -2793,7 +2831,7 @@
 				break;
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2801,7 +2839,7 @@
 				printk(KERN_DEBUG "es1371: midi timed out??\n");
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
 	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2910,6 +2948,11 @@
 	{ SOUND_MIXER_WRITE_IGAIN, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+				 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_es1371(void)
 {
 	struct es1371_state *s;
@@ -2920,11 +2963,10 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.15 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.17 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
-		if (pcidev->resource[0].flags == 0 || 
-		    (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (!RSRCISIOREGION(pcidev, 0))
 			continue;
 		if (pcidev->irq == 0) 
 			continue;
@@ -2940,8 +2982,9 @@
 		init_waitqueue_head(&s->midi.iwait);
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
+		spin_lock_init(&s->lock);
 		s->magic = ES1371_MAGIC;
-		s->io = pcidev->resource[0].start;
+		s->io = RSRCADDRESS(pcidev, 0);
 		s->irq = pcidev->irq;
 		pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
 		if (check_region(s->io, ES1371_EXTENT)) {
@@ -3106,12 +3149,12 @@
 
 static int __init es1371_setup(char *str)
 {
-	static unsigned __initdata nr_dev = 0;
+	static unsigned __initlocaldata nr_dev = 0;
 
 	if (nr_dev >= NR_DEVICE)
 		return 0;
 	if (get_option(&str, &joystick[nr_dev]) == 2)
-		get_option(&str, &spdif[nr_dev]);
+		(void)get_option(&str, &spdif[nr_dev]);
 	nr_dev++;
 	return 1;
 }
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- v2.3.16/linux/drivers/sound/esssolo1.c	Thu Aug 12 12:21:48 1999
+++ linux/drivers/sound/esssolo1.c	Tue Sep  7 10:19:45 1999
@@ -54,6 +54,10 @@
  *                     The fun part is that the Windows Solo1 driver doesn't
  *                     seem to do these tricks.
  *                     Bugs remaining: plops and clicks when starting/stopping playback
+ *    31.08.99   0.7   add spin_lock_init
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.8   change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  */
 
@@ -929,7 +933,7 @@
 	
 	if (s->dma_dac.mapped)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -941,7 +945,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
@@ -953,7 +957,7 @@
                         printk(KERN_DEBUG "solo1: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1599,6 +1603,7 @@
 static ssize_t solo1_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1609,7 +1614,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -1620,15 +1628,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -1637,13 +1655,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t solo1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct solo1_state *s = (struct solo1_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1654,7 +1676,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -1667,15 +1692,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -1688,6 +1723,8 @@
 		solo1_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -1779,7 +1816,7 @@
 	VALIDATE_STATE(s);
 
 	if (file->f_mode & FMODE_WRITE) {
-		current->state = TASK_INTERRUPTIBLE;
+		__set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&s->midi.owait, &wait);
 		for (;;) {
 			spin_lock_irqsave(&s->lock, flags);
@@ -1791,7 +1828,7 @@
 				break;
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -1799,7 +1836,7 @@
 				printk(KERN_DEBUG "solo1: midi timed out??\n");
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
 	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2030,6 +2067,11 @@
 	{ SOUND_MIXER_WRITE_MIC, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+				 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
+
 static int __init init_solo1(void)
 {
 	struct solo1_state *s;
@@ -2039,17 +2081,13 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.6 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.7 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
-		if (pcidev->resource[0].start == 0 ||
-		    (pcidev->resource[0].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
-		    pcidev->resource[1].start == 0 ||
-		    (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
-		    pcidev->resource[2].start == 0 ||
-		    (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO ||
-		    pcidev->resource[3].start == 0 ||
-		    (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (!RSRCISIOREGION(pcidev, 0) ||
+		    !RSRCISIOREGION(pcidev, 1) ||
+		    !RSRCISIOREGION(pcidev, 2) ||
+		    !RSRCISIOREGION(pcidev, 3))
 			continue;
 		if (pcidev->irq == 0)
 			continue;
@@ -2064,14 +2102,15 @@
 		init_waitqueue_head(&s->midi.iwait);
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
+		spin_lock_init(&s->lock);
 		s->magic = SOLO1_MAGIC;
 		s->pcidev = pcidev;
-		s->iobase = pcidev->resource[0].start;
-		s->sbbase = pcidev->resource[1].start;
-		s->vcbase = pcidev->resource[2].start;
+		s->iobase = RSRCADDRESS(pcidev, 0);
+		s->sbbase = RSRCADDRESS(pcidev, 1);
+		s->vcbase = RSRCADDRESS(pcidev, 2);
 		s->ddmabase = s->vcbase + DDMABASE_OFFSET;
-		s->mpubase = pcidev->resource[3].start;
-		s->gpbase = pcidev->resource[4].start;
+		s->mpubase = RSRCADDRESS(pcidev, 3);
+		s->gpbase = RSRCADDRESS(pcidev, 4);
 		s->irq = pcidev->irq;
 		if (check_region(s->iobase, IOBASE_EXTENT) ||
 		    check_region(s->sbbase, SBBASE_EXTENT) ||
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- v2.3.16/linux/drivers/sound/maestro.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/sound/maestro.c	Tue Sep  7 10:14:37 1999
@@ -69,15 +69,29 @@
  *	Once input is actually written, it will be worth pointing out
  *	that only 44/16 input actually works.
  *
+ * History
+ *  v0.04 - Sep 01 1999 - Zach Brown <zab@redhat.com>
+ *	copied memory leak fix from sonicvibes driver
+ *	different ac97 reset, play with 2.0 ac97, simplify ring bus setup
+ *	bob freq code, region sanity, jitter sync fix; all from eric 
+ *
  * TODO
- *	Leaks memory?
  *	recording is horribly broken
- *	apus or dmas get out sync
- *	bob can be started twice
+ *	codec timeouts (we're way under the example source's 20ms(!?))
+ *	some people get indir reg timeouts?
+ *	mixer interface broken?
  *	anyone have a pt101 codec?
  *	ess's ac97 codec (es1921) doesn't work
- *	generally test across codecs..
  *	mmap(), but beware stereo encoding nastiness.
+ *	actually post pci writes
+ *	check for bogon bios set irq/io windows
+ *	compare our pci setup to the dos one, explains register timeouts?
+ *	look really hard at the apu/bob/dma buffer code paths.
+ *
+ *	the entire issue of smp safety needs to be looked at.  cli() needs
+ *	to be replaced with spinlock_irqsave, being very careful of call
+ *	paths avoiding deadlock.  if lock hold times are quick just
+ *	use one big ass per device spinlock.. 
  */
 
 /*****************************************************************************/
@@ -124,7 +138,7 @@
 
 /* --------------------------------------------------------------------- */
 
-#define DRIVER_VERSION "0.03"
+#define DRIVER_VERSION "0.04"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS			0x125D
@@ -293,22 +307,21 @@
 	 
 	for(i=0;i<10000;i++)
 	{
-		if(!(inb(io+ESS_AC97_INDEX)&1))
+		if(!(inb(io+ESS_AC97_INDEX)&1)) 
 			break;
 	}
 	/*
 	 *	Write the bus
 	 */ 
 	outw(val, io+ESS_AC97_DATA);
-	udelay(1);
-	/* should actually be delaying 10 milliseconds? */
+	mdelay(1);
 	outb(cmd, io+ESS_AC97_INDEX);
-	udelay(1);
+	mdelay(1);
 }
 
 static u16 maestro_ac97_get(int io, u8 cmd)
 {
-	int sanity=100000;
+	int sanity=10000;
 	u16 data;
 	int i;
 	
@@ -323,7 +336,7 @@
 	}
 
 	outb(cmd|0x80, io+ESS_AC97_INDEX);
-	udelay(1);
+	mdelay(1);
 	
 	while(inb(io+ESS_AC97_INDEX)&1)
 	{
@@ -335,7 +348,7 @@
 		}
 	}
 	data=inw(io+ESS_AC97_DATA);
-	udelay(1);
+	mdelay(1);
 	return data;
 }
 
@@ -349,28 +362,36 @@
  
 static u16 maestro_ac97_init(int iobase)
 {
-
 	int val, seid, caps;
 	u16 vend1, vend2;
 
-#if 0 /* an experiment for another time */
-		/* aim at the second codec */
-		outw(0x21, iobase+0x38);
-		outw(0x5555, iobase+0x3a);
-		outw(0x5555, iobase+0x3c);
-		udelay(1);
-		vend1 = maestro_ac97_get(iobase, 0x7c);
-		vend2 = maestro_ac97_get(iobase, 0x7e);
-		if(vend1 != 0xffff || vend2 != 0xffff) {
-			printk("maestro: It seems you have a second codec: %x %x, please report this.\n",
-				vend1,vend2);
-		}
-		/* back to the first */
+#if 0  /* this needs to be thought about harder */
+	/* aim at the second codec */
+	outw(0x21, iobase+0x38);
+	outw(0x5555, iobase+0x3a);
+	outw(0x5555, iobase+0x3c);
+	udelay(1);
+	vend1 = maestro_ac97_get(iobase, 0x7c);
+	vend2 = maestro_ac97_get(iobase, 0x7e);
+	if(vend1 != 0xffff || vend2 != 0xffff) {
+		printk("maestro: second codec 0x%4x%4x found, enabling both.  please report this.\n",
+			vend1,vend2);
+		/* enable them both */
+		outw(0x00, iobase+0x38);
+		outw(0xFFFC, iobase+0x3a);
+		outw(0x000C, iobase+0x3c);
+	} else {
+		/* back to the first only */
 		outw(0x0, iobase+0x38);
 		outw(0x0, iobase+0x3a);
 		outw(0x0, iobase+0x3c);
+	}
+	udelay(1);
 #endif
 
+	/* perform codec reset */
+	maestro_ac97_set(iobase, 0x00, 0x0000);
+
 	/* should make sure we're ac97 2.1? */
 	vend1 = maestro_ac97_get(iobase, 0x7c);
 	vend2 = maestro_ac97_get(iobase, 0x7e);
@@ -382,9 +403,15 @@
 	printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x 3d: 0x%x caps: 0x%x\n",
 		vend1,vend2,seid, caps);
 
+	/* XXX endianness, dork head. */
+	/* magic vendor specifc init code, _no_ idea what these do */
 	switch ((long)(vend1 << 16) | vend2) {
-		/* magic vendor specifc init code, _no_ idea what these do */
-#if 0
+	case 0x545200ff:	/* TriTech */
+		
+		maestro_ac97_set(iobase,0x2a,0x0001);
+		maestro_ac97_set(iobase,0x2c,0x0000);
+		maestro_ac97_set(iobase,0x2c,0xffff);
+		break;
 	case 0x83847609:	/* ESS 1921 */
 		maestro_ac97_set(iobase,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
 		udelay(20);
@@ -393,7 +420,6 @@
 		maestro_ac97_set(iobase,0x78,0x3802);
 		udelay(20);
 		break;
-#endif
 	default: break;
 	}
 
@@ -424,6 +450,15 @@
 	/* power up various units? */
 	maestro_ac97_set(iobase, 0x26, 0x000F);
 
+	/* lets see if they actually default to the spec :) */
+	if(maestro_ac97_get(iobase,0x36) ==0x8080) {
+		int reg;
+		printk("maestro: your ac97 might be 2.0, see if this makes sense:\n");
+		for(reg = 0x28; reg <= 0x58 ; reg += 2) {
+			printk("   0x%2x: %4x\n",reg,maestro_ac97_get(iobase,reg));
+		}
+	}
+
 	return 0;
 }
 
@@ -450,10 +485,43 @@
 
 static void maestro_ac97_reset(int ioaddr)
 {
+/*	outw(0x2000,  ioaddr+0x36);
+	inb(ioaddr);
+	mdelay(1);
+	outw(0x0000,  ioaddr+0x36);
+	inb(ioaddr);
+	mdelay(1);*/
+
+	/* well this seems to work a little
+		better on the 2e */
+	/* this screws around with the gpio
+		mask/input/direction.. */
+	outw(0x0000,  ioaddr+0x36);
+	udelay(20);
+	outw(0xFFFE,  ioaddr+0x64);
+	outw(0x1,  ioaddr+0x68);
+	outw(0x0,  ioaddr+0x60);
+	udelay(20);
+	outw(0x1,  ioaddr+0x60);
+	udelay(20); /* other source says 500ms.. INSANE */
 	outw(0x2000,  ioaddr+0x36);
 	udelay(20);
-	outw(0x0000,  ioaddr+0x36);
+	outw(0x3000,  ioaddr+0x36);
 	udelay(200);
+	outw(0x0001,  ioaddr+0x68);
+	outw(0xFFFF,  ioaddr+0x64);
+
+	/* strange strange reset tickling the ring bus */
+	outw(0x0, ioaddr+0x36);
+	udelay(20);
+	outw(0x200, ioaddr+0x36); /* first codec only */
+	udelay(20);
+	outw(0x0, ioaddr+0x36);
+	udelay(20);
+	outw(0x2000, ioaddr+0x36);
+	udelay(20);
+	outw(0x3000, ioaddr+0x36);
+	udelay(20);
 }
 
 /*
@@ -621,9 +689,9 @@
 static void sound_reset(int ioaddr)
 {
 	outw(0x2000, 0x18+ioaddr);
-	udelay(10);
+	udelay(1);
 	outw(0x0000, 0x18+ioaddr);
-	udelay(10);
+	udelay(1);
 }
 
 static void set_apu_fmt(struct ess_state *s, int apu, int mode)
@@ -790,9 +858,9 @@
 /*		apu_set_register(ess, channel, 2, (rate&0xFF)<<8|0x10);
 		apu_set_register(ess, channel, 3, rate>>8);*/
 		
+/* XXX think about endianess when writing these registers */
 		/* Load the buffer into the wave engine */
 		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
-		/* XXX reg is little endian.. */
 		apu_set_register(ess, channel, 5, pa&0xFFFF);
 		apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
 		/* setting loop == sample len */
@@ -949,7 +1017,7 @@
 
 #else
 
-/* nice HW BOB implementation.  cheers, eric. */
+/* nice HW BOB implementation. */
 
 static void stop_bob(struct ess_state *s)
 {
@@ -961,17 +1029,51 @@
 /* eventually we could be clever and limit bob ints
 	to the frequency at which our smallest duration
 	chunks may expire */
+#define ESS_SYSCLK	50000000
 static void start_bob(struct ess_state *s)
 {
-	stop_bob(s);	// make sure bob's not already running
+	int prescale;
+	int divide;
+	
+	int freq = 200;		/* requested frequency - calculate what we want here. */
+	
+	stop_bob(s);	/* make sure bob's not already running */
 	
-	maestro_write(s, 6, 0x8000 |(1<<12) | (5<<5) | 11);		// (50MHz/2^14)/12 = 254 Hz = 40 mS
+	/* compute ideal interrupt frequency for buffer size & play rate */
+	/* first, find best prescaler value to match freq */
+	for(prescale=5;prescale<12;prescale++)
+		if(freq > (ESS_SYSCLK>>(prescale+9)))
+			break;
+			
+	/* next, back off prescaler whilst getting divider into optimum range */
+	divide=1;
+	while((prescale > 5) && (divide<32))
+	{
+		prescale--;
+		divide <<=1;
+	}
+	divide>>=1;
+	
+	/* now fine-tune the divider for best match */
+	for(;divide<31;divide++)
+		if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))
+			break;
+	
+	/* divide = 0 is illegal, but don't let prescale = 4! */
+	if(divide == 0)
+	{
+		divide++;
+		if(prescale>5)
+			prescale--;
+	}
+
+	maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */
 	
 	/* Now set IDR 11/17 */
 	maestro_write(s, 0x11, maestro_read(s, 0x11)|1);
 	maestro_write(s, 0x17, maestro_read(s, 0x17)|1);
 }
-#endif // ESS_HW_TIMER
+#endif /* ESS_HW_TIMER */
 /* --------------------------------------------------------------------- */
 
 static int adc_active = 0;
@@ -986,8 +1088,8 @@
 	apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);
 	apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);
 	adc_active&=~1;
-//	if(!adc_active)
-//		stop_bob(s);
+/*	if(!adc_active)
+		stop_bob(s); */
 	spin_unlock_irqrestore(&s->lock, flags);
 }	
 
@@ -1000,8 +1102,8 @@
 	apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);
 	apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);
 	adc_active&=~2;
-//	if(!adc_active)
-//		stop_bob(s);
+/*	if(!adc_active)
+		stop_bob(s); */
 	spin_unlock_irqrestore(&s->lock, flags);
 }	
 
@@ -1020,8 +1122,8 @@
 			apu_set_register(s, 1, 0, 
 				(apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);
 	}
-//	if(!adc_active)
-//		start_bob(s);
+/*	if(!adc_active)
+		start_bob(s);*/
 	adc_active|=2;
 	spin_unlock_irqrestore(&s->lock, flags);
 }	
@@ -1039,8 +1141,8 @@
 		apu_set_register(s, 3, 0, 
 			(apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);
 	}
-//	if(!adc_active)
-//		start_bob(s);
+/*	if(!adc_active)
+		start_bob(s); */
 	adc_active|=1;
 	spin_unlock_irqrestore(&s->lock, flags);
 }	
@@ -1094,8 +1196,9 @@
 		db->ready = db->mapped = 0;
 
 		/* alloc as big a chunk as we can */
-		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER && !db->rawbuf; order--)
-			db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order);
+		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
+			if((db->rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+				break;
 
 		if (!db->rawbuf)
 			return -ENOMEM;
@@ -1144,10 +1247,10 @@
 		/* program enhanced mode registers */
 		/* FILL */
 	} else {
-		//set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift);
+		/* set_dmaa(s, virt_to_bus(db->rawbuf), db->numfrag << db->fragshift); */
 		/* program enhanced mode registers */
 		/* FILL */
-		//set_dac_rate(s, s->ratedac);	// redundant
+		/*set_dac_rate(s, s->ratedac);	 redundant */
 		ess_play_setup(s, fmt, s->ratedac, 
 			db->rawbuf, db->numfrag << db->fragshift);
 	}
@@ -1156,6 +1259,7 @@
 	return 0;
 }
 
+/* XXX haha, way broken with our split stereo setup.  giggle. */
 extern __inline__ void clear_advance(struct ess_state *s)
 {
 	unsigned char c = (s->fmt & (ESS_CFMT_16BIT << ESS_CFMT_ASHIFT)) ? 0 : 0x80;
@@ -1180,9 +1284,9 @@
 	unsigned hwptr;
 	int diff;
 
+/* ADC is way broken.  compare to DAC.. */
 	/* update ADC pointer */
 	if (s->dma_adc.ready) {
-		M_printk("adc ready.. \n");
 		hwptr = (/*s->dma_adc.dmasize - */get_dmac(s)) % s->dma_adc.dmasize;
 		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
 		s->dma_adc.hwptr = hwptr;
@@ -1193,16 +1297,17 @@
 		if (!s->dma_adc.mapped) {
 			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
 				s->enable &= ~ESS_ENABLE_RE;
-				/* FILL ME */
-//				wrindir(s, SV_CIENABLE, s->enable);
-				stop_adc(s);
+				/* FILL ME 
+				wrindir(s, SV_CIENABLE, s->enable); */
+				stop_adc(s); 
 				s->dma_adc.error++;
 			}
 		}
 	}
 	/* update DAC pointer */
 	if (s->dma_dac.ready) {
-		hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize;
+		/* this is so gross.  */
+		hwptr = (/*s->dma_dac.dmasize -*/ get_dmaa(s)) % s->dma_dac.dmasize; 
 		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
 /*		M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
 		s->dma_dac.hwptr = hwptr;
@@ -1213,12 +1318,17 @@
 				wake_up(&s->dma_dac.wait);
 		} else {
 			s->dma_dac.count -= diff;
+/*			M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
 			if (s->dma_dac.count <= 0) {
 				s->enable &= ~ESS_ENABLE_PE;
-/* FILL ME */
-//				wrindir(s, SV_CIENABLE, s->enable);
-
+				/* FILL ME 
+				wrindir(s, SV_CIENABLE, s->enable); */
+				/* XXX how on earth can calling this with the lock held work.. */
 				stop_dac(s);
+				/* brute force everyone back in sync, sigh */
+				s->dma_dac.count = 0; 
+				s->dma_dac.swptr = 0; 
+				s->dma_dac.hwptr = 0; 
 				s->dma_dac.error++;
 			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
 				clear_advance(s);
@@ -1708,8 +1818,8 @@
 				set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
 				/* program enhanced mode registers */
 				/* FILL ME */
-//				wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
-//				wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1);
+/*				wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
+				wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */
 				s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
 				spin_unlock_irqrestore(&s->lock, flags);
 			}
@@ -1739,9 +1849,7 @@
 {  
 	/* oh, bother.	stereo decoding APU's don't work in 16bit so we
 	use dual linear decoders.  which means we have to hack up stereo
-	buffer's we're given.  yuck. 
-
-	and we have to be able to work a byte at a time..*/
+	buffer's we're given.  yuck.  */
 
 	unsigned char *so,*left,*right;
 	int i;
@@ -1780,6 +1888,8 @@
 	unsigned char *splitbuf = NULL;
 	int cnt;
 
+/*	printk("maestro: ess_write: count %d\n", count);*/
+	
 	VALIDATE_STATE(s);
 	if (ppos != &file->f_pos)
 		return -ESPIPE;
@@ -1789,7 +1899,7 @@
 		return ret;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
-	/* I wish we could be more clever than this */
+	/* XXX be more clever than this.. */
 	if (!(splitbuf = kmalloc(count,GFP_KERNEL)))
 		return -ENOMEM; 
 	ret = 0;
@@ -1840,8 +1950,8 @@
 				spin_lock_irqsave(&s->lock, flags);
 				set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
 				/* program enhanced mode registers */
-//				wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
-//				wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1);
+/*				wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
+				wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */
 				/* FILL ME */
 				s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
 				spin_unlock_irqrestore(&s->lock, flags);
@@ -1957,6 +2067,8 @@
 	int val, mapped, ret;
 	unsigned char fmtm, fmtd;
 
+/*	printk("maestro: ess_ioctl: cmd %d\n", cmd);*/
+	
 	VALIDATE_STATE(s);
         mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
 		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
@@ -2248,7 +2360,6 @@
                 return -EINVAL;
 		
 	}
-//	return mixer_ioctl(s, cmd, arg);
 	return -EINVAL;
 }
 
@@ -2374,7 +2485,7 @@
 static int maestro_install(struct pci_dev *pcidev, int card_type, int index)
 {
 	u16 w;
-	u32 n;
+/*	u32 n;*/
 	int iobase;
 	int i;
 	struct ess_card *card;
@@ -2384,6 +2495,12 @@
 			
 	iobase = pcidev->resource[0].start;
 
+	if(check_region(iobase, 256))
+	{
+		printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
+		return 0;
+	}
+
 	card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
 	if(card == NULL)
 	{
@@ -2531,14 +2648,37 @@
 	 
 	pci_write_config_word(pcidev, 0x40, w);
 
+	/* stake our claim on the iospace */
+	request_region(iobase, 256, card_names[card_type]);
+	
 	sound_reset(iobase);
+#if 0
+
+	/* reset the ring bus */
+
+	outw(inw(iobase + 0x36) & 0xdfff,  iobase+0x36); /* disable */
+	outw(0xC090, iobase+0x34);
+	udelay(20);
+	outw(inw(iobase + 0x36) |0x2000,  iobase+0x36); /* enable */
+#endif
+	/*
+	 *	Ring Bus Setup
+	 */
+
+	/* setup usual 0x34 stuff.. 0x36 may be chip specific */
+        outw(0xC090, iobase+0x34); /* direct sound, stereo */
+        udelay(20);
+        outw(0x3000, iobase+0x36); /* direct sound, stereo */
+        udelay(20);
+
 
 	/*
 	 *	Reset the CODEC
 	 */
 	 
 	maestro_ac97_reset(iobase);
-		
+	
+#if 0
 	/*
 	 *	Ring Bus Setup
 	 */
@@ -2546,6 +2686,7 @@
 	n=inl(iobase+0x34);
 	n&=~0xF000;
 	n|=12<<12;		/* Direct Sound, Stereo */
+	outl(n, iobase+0x34);
 
 	n=inl(iobase+0x34);
 	n&=~0x0F00;		/* Modem off */
@@ -2605,11 +2746,15 @@
 	w=inw(iobase+0x18);
 	w|=(1<<0);		/* SB IRQ on */
 	outw(w, iobase+0x18);
+#endif
 
 
-	outb(0, iobase+0xA4);
-	outb(3, iobase+0xA2);
+#if 0
+	/* asp crap */
+	outb(0, iobase+0xA4); 
+	outb(3, iobase+0xA2); 
 	outb(0, iobase+0xA6);
+#endif
 	
 	for(apu=0;apu<16;apu++)
 	{
@@ -2698,10 +2843,18 @@
 	if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, card_names[card_type], card))
 	{
 		printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
+		unregister_sound_mixer(card->dev_mixer);
+		for(i=0;i<8;i++)
+		{
+			struct ess_state *s = &card->channels[i];
+			if(s->dev_audio != -1)
+				unregister_sound_dsp(s->dev_audio);
+		}
+		release_region(card->iobase, 256);		
+		kfree(card);
 		return 0;
 	}
 
-//	ess_play_test(ess);
 	printk("maestro: %d channels configured.\n", num);
 	return 1; 
 }
@@ -2776,18 +2929,11 @@
 	while ((s = devs)) {
 		int i;
 		devs = devs->next;
-//		ess_play_test(&s->channels[0]);
 #ifndef ESS_HW_TIMER
 		kill_bob(&s->channels[0]);
 #else
 		stop_bob(&s->channels[0]);
 #endif
-//		outb(~0, s->ioenh + SV_CODEC_INTMASK);  /* disable ints */
-//		synchronize_irq();
-//		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
-//		wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-		//outb(0, s->iodmaa + SV_DMA_RESET);
-		//outb(0, s->iodmac + SV_DMA_RESET);
 		free_irq(s->irq, s);
 		unregister_sound_mixer(s->dev_mixer);
 		for(i=0;i<8;i++)
@@ -2796,6 +2942,7 @@
 			if(ess->dev_audio != -1)
 				unregister_sound_dsp(ess->dev_audio);
 		}
+		release_region(s->iobase, 256);
 		kfree(s);
 	}
 	M_printk("maestro: unloading\n");
@@ -2808,6 +2955,7 @@
  *  ex-code that we're not using anymore..
  *============================================================================
  */
+
 /*
  *	The ASSP is fortunately not double indexed
  */
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.3.16/linux/drivers/sound/sonicvibes.c	Thu Aug 12 12:21:48 1999
+++ linux/drivers/sound/sonicvibes.c	Tue Sep  7 10:19:45 1999
@@ -74,6 +74,13 @@
  *    03.08.99   0.17  adapt to Linus' new __setup/__initcall
  *                     added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
  *    12.08.99   0.18  module_init/__setup fixes
+ *    24.08.99   0.19  get rid of the dmaio kludge, replace with allocate_resource
+ *    31.08.99   0.20  add spin_lock_init
+ *                     __initlocaldata to fix gcc 2.7.x problems
+ *                     use new resource allocation to allocate DDMA IO space
+ *                     replaced current->state = x with set_current_state(x)
+ *    03.09.99   0.21  change read semantics for MIDI to match
+ *                     OSS more closely; remove possible wakeup race
  *
  */
 
@@ -121,6 +128,12 @@
 #define SV_EXTENT_GAME    0x8
 #define SV_EXTENT_DMA     0x10
 
+#define RESOURCE_SB       0
+#define RESOURCE_ENH      1
+#define RESOURCE_SYNTH    2
+#define RESOURCE_MIDI     3
+#define RESOURCE_GAME     4
+#define RESOURCE_DDMA     7
 
 #define SV_MIDI_DATA      0
 #define SV_MIDI_COMMAND   1
@@ -1254,7 +1267,7 @@
 
 	if (s->dma_dac.mapped || !s->dma_dac.ready)
 		return 0;
-        current->state = TASK_INTERRUPTIBLE;
+        __set_current_state(TASK_INTERRUPTIBLE);
         add_wait_queue(&s->dma_dac.wait, &wait);
         for (;;) {
                 spin_lock_irqsave(&s->lock, flags);
@@ -1266,7 +1279,7 @@
                         break;
                 if (nonblock) {
                         remove_wait_queue(&s->dma_dac.wait, &wait);
-                        current->state = TASK_RUNNING;
+                        set_current_state(TASK_RUNNING);
                         return -EBUSY;
                 }
 		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
@@ -1275,7 +1288,7 @@
 			printk(KERN_DEBUG "sv: dma timed out??\n");
         }
         remove_wait_queue(&s->dma_dac.wait, &wait);
-        current->state = TASK_RUNNING;
+        set_current_state(TASK_RUNNING);
         if (signal_pending(current))
                 return -ERESTARTSYS;
         return 0;
@@ -1874,6 +1887,7 @@
 static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1884,7 +1898,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_WRITE, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+	add_wait_queue(&s->midi.iwait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.ird;
@@ -1895,15 +1912,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+                      if (file->f_flags & O_NONBLOCK) {
+                              if (!ret)
+                                      ret = -EAGAIN;
+                              break;
+                      }
+                      __set_current_state(TASK_INTERRUPTIBLE);
+                      schedule();
+                      if (signal_pending(current)) {
+                              if (!ret)
+                                      ret = -ERESTARTSYS;
+                              break;
+                      }
 			continue;
 		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIINBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.ird = ptr;
@@ -1912,13 +1939,17 @@
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
+		break;
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.iwait, &wait);
 	return ret;
 }
 
 static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
 {
 	struct sv_state *s = (struct sv_state *)file->private_data;
+	DECLARE_WAITQUEUE(wait, current);
 	ssize_t ret;
 	unsigned long flags;
 	unsigned ptr;
@@ -1929,7 +1960,10 @@
 		return -ESPIPE;
 	if (!access_ok(VERIFY_READ, buffer, count))
 		return -EFAULT;
+	if (count == 0)
+		return 0;
 	ret = 0;
+        add_wait_queue(&s->midi.owait, &wait);
 	while (count > 0) {
 		spin_lock_irqsave(&s->lock, flags);
 		ptr = s->midi.owr;
@@ -1942,15 +1976,25 @@
 		if (cnt > count)
 			cnt = count;
 		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
+			if (file->f_flags & O_NONBLOCK) {
+				if (!ret)
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if (!ret)
+					ret = -ERESTARTSYS;
+				break;
+			}
 			continue;
 		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
+		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
+			if (!ret)
+				ret = -EFAULT;
+			break;
+		}
 		ptr = (ptr + cnt) % MIDIOUTBUF;
 		spin_lock_irqsave(&s->lock, flags);
 		s->midi.owr = ptr;
@@ -1963,6 +2007,8 @@
 		sv_handle_midi(s);
 		spin_unlock_irqrestore(&s->lock, flags);
 	}
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&s->midi.owait, &wait);
 	return ret;
 }
 
@@ -2057,7 +2103,7 @@
 	VALIDATE_STATE(s);
 
 	if (file->f_mode & FMODE_WRITE) {
-		current->state = TASK_INTERRUPTIBLE;
+		__set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&s->midi.owait, &wait);
 		for (;;) {
 			spin_lock_irqsave(&s->lock, flags);
@@ -2069,7 +2115,7 @@
 				break;
 			if (file->f_flags & O_NONBLOCK) {
 				remove_wait_queue(&s->midi.owait, &wait);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				return -EBUSY;
 			}
 			tmo = (count * HZ) / 3100;
@@ -2077,7 +2123,7 @@
 				printk(KERN_DEBUG "sv: midi timed out??\n");
 		}
 		remove_wait_queue(&s->midi.owait, &wait);
-		current->state = TASK_RUNNING;
+		set_current_state(TASK_RUNNING);
 	}
 	down(&s->open_sem);
 	s->open_mode &= (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE);
@@ -2296,8 +2342,6 @@
 static int wavetable[NR_DEVICE] = { 0, };
 #endif
 
-static unsigned dmaio = 0xac00;
-
 MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i");
 MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
 #if 0
@@ -2305,9 +2349,6 @@
 MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
 #endif
 
-MODULE_PARM(dmaio, "i");
-MODULE_PARM_DESC(dmaio, "if the motherboard BIOS did not allocate DDMA io, allocate them starting at this address");
-
 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 MODULE_DESCRIPTION("S3 SonicVibes Driver");
 
@@ -2328,33 +2369,54 @@
 	{ SOUND_MIXER_WRITE_PCM, 0x4040 }
 };
 
+#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
+				 ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+
 static int __init init_sonicvibes(void)
 {
-	struct sv_state *s;
+	static const char __initlocaldata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
+       	struct sv_state *s;
 	struct pci_dev *pcidev = NULL;
 	mm_segment_t fs;
 	int i, val, index = 0;
+	char *ddmaname;
+	unsigned ddmanamelen;
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.18 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.20 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
 #endif
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, pcidev))) {
-		if (pcidev->resource[1].flags == 0 || 
-		    (pcidev->resource[1].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-			continue;
-		if (pcidev->resource[2].flags == 0 || 
-		    (pcidev->resource[2].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
-			continue;
-		if (pcidev->resource[3].flags == 0 || 
-		    (pcidev->resource[3].flags & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_IO)
+		if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
+		    !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
+		    !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
+		    !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
+		    !RSRCISIOREGION(pcidev, RESOURCE_GAME))
 			continue;
 		if (pcidev->irq == 0)
 			continue;
+		/* try to allocate a DDMA resource if not already available */
+		if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
+			/* take care of ISA aliases */
+			ddmanamelen = strlen(sv_ddma_name)+1;
+			if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
+				continue;
+			memcpy(ddmaname, sv_ddma_name, ddmanamelen);
+			pcidev->resource[RESOURCE_DDMA].name = ddmaname;
+			if (allocate_resource(&ioport_resource, pcidev->resource+RESOURCE_DDMA, 
+					      2*SV_EXTENT_DMA, 0x1000, 0x10000-2*SV_EXTENT_DMA, 1024)) {
+				pcidev->resource[RESOURCE_DDMA].name = NULL;
+				kfree(ddmaname);
+				printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
+				continue;
+			}
+			pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
+		}
 		if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
 			printk(KERN_WARNING "sv: out of memory\n");
 			continue;
@@ -2366,35 +2428,19 @@
 		init_waitqueue_head(&s->midi.iwait);
 		init_waitqueue_head(&s->midi.owait);
 		init_MUTEX(&s->open_sem);
+		spin_lock_init(&s->lock);
 		s->magic = SV_MAGIC;
-		s->iosb = pcidev->resource[0].start;
-		s->ioenh = pcidev->resource[1].start;
-		s->iosynth = pcidev->resource[2].start;
-		s->iomidi = pcidev->resource[3].start;
-		s->iogame = pcidev->resource[4].start;
-		pci_read_config_dword(pcidev, 0x40, &s->iodmaa);
-		pci_read_config_dword(pcidev, 0x48, &s->iodmac);
-		dmaio &= ~(SV_EXTENT_DMA-1);
-		s->iodmaa &= ~(SV_EXTENT_DMA-1);
-		s->iodmac &= ~(SV_EXTENT_DMA-1);
-		if (!(s->iodmaa)) {
-			s->iodmaa = dmaio;
-			dmaio += SV_EXTENT_DMA;
-			printk(KERN_INFO "sv: BIOS did not allocate DDMA channel A io, allocated at %#x\n",
-			       s->iodmaa);
-		}
-		if (!(s->iodmac)) {
-			s->iodmac = dmaio;
-			dmaio += SV_EXTENT_DMA;
-			printk(KERN_INFO "sv: BIOS did not allocate DDMA channel C io, allocated at %#x\n",
-			       s->iodmac);
-		}
+		s->iosb = RSRCADDRESS(pcidev, RESOURCE_SB);
+		s->ioenh = RSRCADDRESS(pcidev, RESOURCE_ENH);
+		s->iosynth = RSRCADDRESS(pcidev, RESOURCE_SYNTH);
+		s->iomidi = RSRCADDRESS(pcidev, RESOURCE_MIDI);
+		s->iogame = RSRCADDRESS(pcidev, RESOURCE_GAME);
+		s->iodmaa = RSRCADDRESS(pcidev, RESOURCE_DDMA);
+		s->iodmac = RSRCADDRESS(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
 		pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9);  /* enable and use extended mode */
 		pci_write_config_dword(pcidev, 0x48, s->iodmac | 9);  /* enable */
 		printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n",
 		       s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac);
-		if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0)
-			continue;
 		s->irq = pcidev->irq;
 
 		/* hack */
@@ -2436,8 +2482,8 @@
 		wrindir(s, SV_CIDRIVECONTROL, 0);  /* drive current 16mA */
 		wrindir(s, SV_CIENABLE, s->enable = 0);  /* disable DMAA and DMAC */
 		outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
-		//outb(0xff, s->iodmaa + SV_DMA_RESET);
-		//outb(0xff, s->iodmac + SV_DMA_RESET);
+		/* outb(0xff, s->iodmaa + SV_DMA_RESET); */
+		/* outb(0xff, s->iodmac + SV_DMA_RESET); */
 		inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
 		wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
 		wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
@@ -2550,31 +2596,21 @@
 
 static int __init sonicvibes_setup(char *str)
 {
-	static unsigned __initdata nr_dev = 0;
+	static unsigned __initlocaldata nr_dev = 0;
 
 	if (nr_dev >= NR_DEVICE)
 		return 0;
 #if 0
 	if (get_option(&str, &reverb[nr_dev]) == 2)
-		get_option(&str, &wavetable[nr_dev]);
+		(void)get_option(&str, &wavetable[nr_dev]);
 #else
-	get_option(&str, &reverb[nr_dev]);
+	(void)get_option(&str, &reverb[nr_dev]);
 #endif
 
 	nr_dev++;
 	return 1;
 }
 
-static int __init sonicvibesdmaio_setup(char *str)
-{
-        int io;
-
-	if (get_option(&str, &io))
-		dmaio = io;
-	return 1;
-}
-
 __setup("sonicvibes=", sonicvibes_setup);
-__setup("sonicvibesdmaio=", sonicvibesdmaio_setup);
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.3.16/linux/drivers/sound/via82cxxx.c linux/drivers/sound/via82cxxx.c
--- v2.3.16/linux/drivers/sound/via82cxxx.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/sound/via82cxxx.c	Tue Sep  7 10:22:12 1999
@@ -0,0 +1,256 @@
+/*
+ * Support for VIA 82Cxxx Audio Codecs
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ *
+ * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2.
+ * See the "COPYING" file distributed with this software for more info.
+ *
+ ********************************************************************
+ *
+ * TODO:
+ *
+ *	- Integrate AC'97 support, when AC'97 interface released
+ *
+ */
+ 
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+#include "sound_config.h"
+#include "soundmodule.h"
+#include "sb.h"
+
+#ifndef SOUND_LOCK
+#define SOUND_LOCK do {} while (0)
+#define SOUND_LOCK_END do {} while (0)
+#endif
+
+#define MAX_CARDS	2
+
+#define PFX		"via82cxxx: "
+
+#define VIA_VERSION	"1.0.0"
+#define VIA_CARD_NAME	"VIA 82Cxxx Audio driver " VIA_VERSION
+
+#define VIA_FUNC_ENABLE		0x42
+#define VIA_PNP_CONTROL		0x43
+
+#define VIA_CR42_SB_ENABLE	0x01
+#define VIA_CR42_MIDI_ENABLE	0x02
+#define VIA_CR42_FM_ENABLE	0x04
+
+#define via_probe_midi probe_uart401
+#define via_attach_midi attach_uart401
+#define via_unload_midi unload_uart401
+
+static struct address_info	sb_data[MAX_CARDS];
+static struct address_info	opl3_data[MAX_CARDS];
+static unsigned			cards = 0;
+
+
+static void __init via_attach_sb(struct address_info *hw_config)
+{
+	if(!sb_dsp_init(hw_config))
+		hw_config->slots[0] = -1;
+}
+
+
+static int __init via_probe_sb(struct address_info *hw_config)
+{
+	if (check_region(hw_config->io_base, 16))
+	{
+		printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
+		       hw_config->io_base);
+		return 0;
+	}
+	return sb_dsp_detect(hw_config, 0, 0);
+}
+
+
+static void __exit via_unload_sb(struct address_info *hw_config, int unload_mpu)
+{
+	if(hw_config->slots[0]!=-1)
+		sb_dsp_unload(hw_config, unload_mpu);
+}
+
+
+static int __init via82cxxx_install (struct pci_dev *pcidev)
+{
+	int sb_io_base = 0;
+	int sb_irq = 0;
+	int sb_dma = 0;
+	int midi_base = 0;
+	u8 tmp8;
+	
+	memset (&sb_data[cards], 0, sizeof (struct address_info));
+	memset (&opl3_data[cards], 0, sizeof (struct address_info));
+
+	sb_data[cards].name = opl3_data[cards].name = VIA_CARD_NAME;
+	opl3_data[cards].irq = -1;
+
+	/* turn on features, if not already */
+	pci_read_config_byte (pcidev, VIA_FUNC_ENABLE, &tmp8);
+	tmp8 |= VIA_CR42_SB_ENABLE | VIA_CR42_MIDI_ENABLE |
+		VIA_CR42_FM_ENABLE;
+	pci_write_config_byte (pcidev, VIA_FUNC_ENABLE, tmp8);
+
+	/* read legacy PNP info byte */
+	pci_read_config_byte (pcidev, VIA_PNP_CONTROL, &tmp8);
+	pci_write_config_byte (pcidev, VIA_PNP_CONTROL, tmp8);
+	
+	switch ((tmp8 >> 6) & 0x03) {
+		case 0: sb_irq = 5; break;
+		case 1: sb_irq = 7; break;
+		case 2: sb_irq = 9; break;
+		case 3: sb_irq = 10; break;
+		default: /* do nothing */ break;
+	}
+	switch ((tmp8 >> 4) & 0x03) {
+		case 0: sb_dma = 0; break;
+		case 1: sb_dma = 1; break;
+		case 2: sb_dma = 2; break;
+		case 3: sb_dma = 3; break;
+		default: /* do nothing */ break;
+	}
+	switch ((tmp8 >> 2) & 0x03) {
+		case 0: midi_base = 0x300; break;
+		case 1: midi_base = 0x310; break;
+		case 2: midi_base = 0x320; break;
+		case 3: midi_base = 0x330; break;
+		default: /* do nothing */ break;
+	}
+	switch (tmp8 & 0x03) {
+		case 0: sb_io_base = 0x220; break;
+		case 1: sb_io_base = 0x240; break;
+		case 2: sb_io_base = 0x260; break;
+		case 3: sb_io_base = 0x280; break;
+		default: /* do nothing */ break;
+	}
+
+	udelay(100);
+	
+	printk(KERN_INFO PFX "legacy "
+	       "MIDI: 0x%X, SB: 0x%X / %d IRQ / %d DMA\n",
+		midi_base, sb_io_base, sb_irq, sb_dma);
+		
+	sb_data[cards].card_subtype = MDL_SBPRO;
+	sb_data[cards].io_base = sb_io_base;
+	sb_data[cards].irq = sb_irq;
+	sb_data[cards].dma = sb_dma;
+	
+	opl3_data[cards].io_base = midi_base;
+	
+	/* register legacy SoundBlaster Pro */
+	if (!via_probe_sb (&sb_data[cards])) {
+		printk (KERN_ERR PFX
+			"SB probe @ 0x%X failed, aborting\n",
+			sb_io_base);
+		return -1;
+	}
+	via_attach_sb (&sb_data[cards]);
+
+	/* register legacy MIDI */
+	if (!via_probe_midi (&opl3_data[cards])) {
+		printk (KERN_ERR PFX
+			"MIDI probe @ 0x%X failed, aborting\n",
+			midi_base);
+		via_unload_sb (&sb_data[cards], 0);
+		return -1;
+	}
+	via_attach_midi (&opl3_data[cards]);
+
+	cards++;	
+	return 0;
+}
+
+
+/*
+ * 	This loop walks the PCI configuration database and finds where
+ *	the sound cards are.
+ */
+ 
+static int __init probe_via82cxxx (void)
+{
+	struct pci_dev *pcidev = NULL;
+
+	while ((pcidev = pci_find_device (PCI_VENDOR_ID_VIA,
+					  PCI_DEVICE_ID_VIA_82C686_5,
+					  pcidev)) != NULL) {
+
+		  if (via82cxxx_install (pcidev) != 0) {
+			  printk (KERN_ERR PFX "audio init failed\n");
+			  return -1;
+		  }
+
+		  if (cards == MAX_CARDS) {
+		  	  printk (KERN_DEBUG PFX "maximum number of cards reached\n");
+			  break;
+		  }
+	}
+
+	return 0;
+}
+
+
+/*
+ *	This function is called when the user or kernel loads the 
+ *	module into memory.
+ */
+
+
+static int __init init_via82cxxx_module(void)
+{
+	if (!pci_present ()) {
+		printk (KERN_DEBUG PFX "PCI not present, exiting\n");
+		return -ENODEV;
+	}
+
+	if (probe_via82cxxx() != 0) {
+		printk(KERN_ERR PFX "probe failed, aborting\n");
+		/* XXX unload cards registered so far, if any */
+		return -ENODEV;
+	}
+
+	if (cards == 0) {
+		printk(KERN_DEBUG PFX "No chips found, aborting\n");
+		return -ENODEV;
+	}
+
+	printk (KERN_INFO PFX VIA_CARD_NAME " loaded\n");
+	
+	/*
+	 *	Binds us to the sound subsystem	
+	 */
+	SOUND_LOCK;
+	return 0;
+}
+
+/*
+ *	This is called when it is removed. It will only be removed 
+ *	when its use count is 0. For sound the SOUND_LOCK/SOUND_UNLOCK
+ *	macros hide the entire work for this.
+ */
+ 
+static void __exit cleanup_via82cxxx_module(void)
+{
+	int i;
+	
+	for (i = 0; i < cards; i++)
+		via_unload_sb (&sb_data[i], 1);
+
+	/*
+	 *	Final clean up with the sound layer
+	 */
+	SOUND_LOCK_END;
+}
+
+module_init(init_via82cxxx_module);
+module_exit(cleanup_via82cxxx_module);
+
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/CREDITS linux/drivers/usb/CREDITS
--- v2.3.16/linux/drivers/usb/CREDITS	Mon Aug  2 14:29:08 1999
+++ linux/drivers/usb/CREDITS	Wed Sep  1 15:31:47 1999
@@ -9,6 +9,7 @@
   ham <ham@unsuave.com>
   Bradley M Keryan <keryan@andrew.cmu.edu>
   Paul Mackerras <paulus@cs.anu.edu.au>
+  David E. Nelson <dnelson@jump.net>
   Vojtech Pavlik <vojtech@twilight.ucw.cz>
   Gregory P. Smith <greg@electricrain.com>
   Linus Torvalds <torvalds@transmeta.com>
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.3.16/linux/drivers/usb/Config.in	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/Config.in	Wed Sep  1 15:31:47 1999
@@ -28,6 +28,7 @@
 
   dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB
   dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+  dep_tristate 'USB HP scanner support' CONFIG_USB_HP_SCANNER $CONFIG_USB
   dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB
   dep_tristate 'USB audio parsing support' CONFIG_USB_AUDIO $CONFIG_USB
   dep_tristate 'USB Communications Device Class (ACM) support' CONFIG_USB_ACM $CONFIG_USB
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.3.16/linux/drivers/usb/Makefile	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/Makefile	Wed Sep  1 15:31:47 1999
@@ -64,6 +64,14 @@
   MIX_OBJS += mouse.o
 endif
 
+ifeq ($(CONFIG_USB_HP_SCANNER),y)
+  L_OBJS += hp_scanner.o
+endif
+ifeq ($(CONFIG_USB_HP_SCANNER),m)
+  M_OBJS  +=hp_scanner.o
+  MIX_OBJS +=hp_scanner.o
+endif
+
 ifeq ($(CONFIG_USB_HUB),y)
   L_OBJS += hub.o
 endif
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/README.hp_scanner linux/drivers/usb/README.hp_scanner
--- v2.3.16/linux/drivers/usb/README.hp_scanner	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/README.hp_scanner	Wed Sep  1 15:31:47 1999
@@ -0,0 +1,59 @@
+August 30, 1999
+
+
+Overview
+
+This README will address issues regarding how to configure the kernel
+to access a USB HP Scanner.  The scanner should support the Scanner
+Control Language (SCL) so that applications such as SANE can access it
+properly.  Refer to the document README.hp_scanner_sane for guidance
+on how to configure SANE to use the USB HP Scanner.
+
+
+Requirements
+
+A host with a USB port.  Ideally, either a UHCI (Intel) or OHCI
+(Compaq and others) hardware port should work.  However, I've only
+been able to really use an OHCI controller.  I did have access to a
+system with a UHCI controller but some very limited testing did not
+produce satisfactory results.
+
+A Linux kernel with USB support (preferably 2.3.15+).
+
+A Linux kernel with USB HP Scanner support.
+
+
+Configuration
+
+Add both USB controller support and USB HP Scanner support using `make
+menuconfig`.  If you decide to use the ohci-hcd driver, don't forget
+to add HUB support.  Compile and install the modules.  Testing was
+performed only as modules, YMMV.
+
+Add a device for the USB scanner: `mknod /dev/usbscanner c 16 1`
+
+Set appropriate permissions for /dev/usbscanner.  Both read and write
+permissions are needed for proper operation.
+
+Load the appropriate modules:
+
+  OHCI:
+
+    modprobe usb-ohci
+    modprobe hp_scanner
+
+  OHCI-HCD:
+    modprobe usb-ohci-hcd
+    modprobe hub
+    modprobe hp_scanner
+
+That's it.  SANE should now be able to access the device.  
+
+There is a small test program (hp_scan.c) that can be used to test the
+scanner device.  It's purpose is to test the driver(s) without having
+to retrieve/configure SANE.  Hp_scan.c will scan the entire bed and
+put the output into a file called out.dat in the current directory.
+The data in the file is raw data.
+
+David /\/elson
+dnelson@jump.net
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/README.hp_scanner_sane linux/drivers/usb/README.hp_scanner_sane
--- v2.3.16/linux/drivers/usb/README.hp_scanner_sane	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/README.hp_scanner_sane	Wed Sep  1 15:31:47 1999
@@ -0,0 +1,67 @@
+August 30, 1999
+
+NOTE: This is all VERY alpha.  Use at your own risk.  There is no
+warranty expressed nor implied.
+
+
+Introduction
+
+This document will hopefully provide enough info on how to get SANE
+working with a Hewlett Packard USB capable scanner using the USB
+interface.  The majority of HP Scanners support the Scanner Control
+Language (SCL) which is both published by HP and supported by SANE.
+The only HP Scanner that I'm aware of that does not support SCL is the
+4200C.  All other HP scanners with USB interfaces should work (4100C,
+5200C, 6200C).  Of course as HP releases new scanners this information
+may change.
+
+
+Requirements
+
+In order to get this running you'll need USB support in your kernel in
+addition to USB HP Scanner support.  Please refer to README.hp_scanner
+for issues pertaining to Linux USB and USB HP Scanner support.
+
+An installed version of SANE which is available from
+http://www.mostang.com/sane/.  Testing has been performed using
+version SANE-1.0.1.  For instructions on building and installing SANE,
+refer to the various README files within the distribution.
+
+
+Ok, so what do I do?
+
+NOTE: $INSTALL_DIR is the location where SANE was installed.  It may
+be /usr/local, /usr, /opt or somewhere else.  If you don't know, ask
+your system administrator.
+
+1) Make sure that you have the libsane-hp.* libraries under the
+$INSTALL_DIR/lib/sane/ directory.
+
+2) Under the directory $INSTALL_DIR/etc/sane.d/ edit the following
+files: dll.conf, hp.conf.
+
+  dll.conf:  Make sure that the 'hp' entry is present and uncommented.
+
+  hp.conf: This should contain two lines:
+
+    option connect-device
+    /dev/usbscanner
+
+3) You should now be able to use SANE (xscanimage or scanimage).
+
+Don't forget to read any relevant man pages regarding the usage of
+SANE.  If you have other entries uncommented in dll.conf, you my have
+to specify the device to (x)scanimage.  The xscanimage (1) man page
+has info on how to get 'The Gimp' to work with xscanimage.  Note that
+Gimp support must be compiled into SANE for it work.  If you are
+dealing with a RedHat system, you'll also need to install the
+gimp-devel rpm package.
+
+NOTE: Most of the time xscanimage will run without incident, then on
+the next invocation it'll core dump at different locations.  I don't
+know why yet and I don't have a work around either other than to try
+again.  But once you get it started, it'll scan without any problems
+(or at least it does for me).
+
+David /\/elson
+dnelson@jump.net
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c
--- v2.3.16/linux/drivers/usb/cpia.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/cpia.c	Wed Sep  1 16:24:19 1999
@@ -597,9 +597,9 @@
 	/* First for desc. [0] */
 	id = cpia->sbuf [0].isodesc;
 	id->start_type = START_ASAP;
-	id->callback_frames = 1;        /* on every frame */
+	id->callback_frames = 10;	/* on every 10th frame */
 	id->callback_fn = cpia_isoc_irq;
-	id->data = cpia->sbuf [0].data;
+	id->data = cpia->sbuf[0].data;
 	id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
 	for (fx = 0; fx < FRAMES_PER_DESC; fx++)
 		id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
@@ -607,15 +607,15 @@
 	/* and the desc. [1] */
 	id = cpia->sbuf [1].isodesc;
 	id->start_type = 0;             /* will follow the first desc. */
-	id->callback_frames = 1;        /* on every frame */
+	id->callback_frames = 10;	/* on every 10th frame */
 	id->callback_fn = cpia_isoc_irq;
-	id->data = cpia->sbuf [1].data;
+	id->data = cpia->sbuf[1].data;
 	id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
 	for (fx = 0; fx < FRAMES_PER_DESC; fx++)
 		id->frames [fx].frame_length = FRAME_SIZE_PER_DESC;
 
-	usb_run_isoc (cpia->sbuf [0].isodesc, NULL);
-	usb_run_isoc (cpia->sbuf [1].isodesc, cpia->sbuf [0].isodesc);
+	usb_run_isoc (cpia->sbuf[0].isodesc, NULL);
+	usb_run_isoc (cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc);
 
 #if 0
 	usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL);
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/cpia.h linux/drivers/usb/cpia.h
--- v2.3.16/linux/drivers/usb/cpia.h	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/cpia.h	Wed Sep  1 16:24:19 1999
@@ -82,7 +82,7 @@
 
 #define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
 
-#define FRAMES_PER_DESC		500
+#define FRAMES_PER_DESC		10
 #define FRAME_SIZE_PER_DESC	960	/* Shouldn't be hardcoded */
 
 enum {
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/ezusb.c linux/drivers/usb/ezusb.c
--- v2.3.16/linux/drivers/usb/ezusb.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/ezusb.c	Tue Sep  7 10:19:45 1999
@@ -26,18 +26,22 @@
  *                  bulk reads.
  *                  Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK.
  *                  Preliminary ISO support
+ *   0.3  01.09.99  Async Bulk and ISO support
+ *   0.4  01.09.99
  *
  */
 
 /*****************************************************************************/
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/socket.h>
-#include <asm/uaccess.h>
 #include <linux/miscdevice.h>
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <asm/spinlock.h>
+#include <asm/uaccess.h>
 
 #include "usb.h"
 #include "ezusb.h"
@@ -49,27 +53,190 @@
 static struct ezusb {
 	struct semaphore mutex;
 	struct usb_device *usbdev;
-	struct list_head iso;
+	struct list_head async_pending;
+	struct list_head async_completed;
+	wait_queue_head_t wait;
+	spinlock_t lock;
 } ezusb[NREZUSB];
 
-struct isodesc {
-	struct list_head isolist;
-	spinlock_t lock;
-	struct usb_device *usbdev;
-	unsigned int ep;
-	unsigned int pipe;
-	unsigned int pktsz;
-	unsigned int framesperint;
-	unsigned int rd, wr, buflen;
-	unsigned int flags;
-	unsigned int schedcnt, unschedcnt;
-
-	void *hcbuf[2];
-	void *hcisodesc[2];
-	unsigned char *buf;
-};     
+struct async {
+	struct list_head asynclist;
+	struct ezusb *ez;
+	void *data;
+	unsigned dataorder;
+	void *userdata;
+	unsigned datalen;
+	union {
+		struct usb_isoc_desc *iso;
+		void *bulk;
+	} desc;
+	unsigned numframes; /* 0 means bulk, > 0 means iso */
+	struct ezusb_asynccompleted completed;
+};
 
-#define ISOFLG_ACTIVE	(1<<0)
+/* --------------------------------------------------------------------- */
+
+extern inline unsigned ld2(unsigned int x)
+{
+        unsigned r = 0;
+        
+        if (x >= 0x10000) {
+                x >>= 16;
+                r += 16;
+        }
+        if (x >= 0x100) {
+                x >>= 8;
+                r += 8;
+        }
+        if (x >= 0x10) {
+                x >>= 4;
+                r += 4;
+        }
+        if (x >= 4) {
+                x >>= 2;
+                r += 2;
+        }
+        if (x >= 2)
+                r++;
+        return r;
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ void async_removelist(struct async *as)
+{
+	struct ezusb *ez = as->ez;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ez->lock, flags);
+	list_del(&as->asynclist);
+	INIT_LIST_HEAD(&as->asynclist);
+	spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ void async_newpending(struct async *as)
+{
+	struct ezusb *ez = as->ez;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&ez->lock, flags);
+	list_add_tail(&as->asynclist, &ez->async_pending);
+	spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ void async_movetocompleted(struct async *as)
+{
+	struct ezusb *ez = as->ez;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ez->lock, flags);
+	list_del(&as->asynclist);
+	list_add_tail(&as->asynclist, &ez->async_completed);
+	spin_unlock_irqrestore(&ez->lock, flags);
+}
+
+extern __inline__ struct async *async_getcompleted(struct ezusb *ez)
+{
+	unsigned long flags;
+	struct async *as = NULL;
+
+	spin_lock_irqsave(&ez->lock, flags);
+	if (!list_empty(&ez->async_completed)) {
+		as = list_entry(ez->async_completed.next, struct async, asynclist);
+		list_del(&as->asynclist);
+		INIT_LIST_HEAD(&as->asynclist);
+	}
+	spin_unlock_irqrestore(&ez->lock, flags);
+	return as;
+}
+
+extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context)
+{
+	unsigned long flags;
+	struct async *as;
+	struct list_head *p;
+
+	spin_lock_irqsave(&ez->lock, flags);
+	for (p = ez->async_pending.next; p != &ez->async_pending; ) {
+		as = list_entry(p, struct async, asynclist);
+		p = p->next;
+		if (as->completed.context != context)
+			continue;
+		list_del(&as->asynclist);
+		INIT_LIST_HEAD(&as->asynclist);
+		spin_unlock_irqrestore(&ez->lock, flags);
+		return as;
+	}
+	spin_unlock_irqrestore(&ez->lock, flags);
+	return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int async_completed(int status, void *__buffer, int rval, void *dev_id)
+{
+	struct async *as = (struct async *)dev_id;
+	struct ezusb *ez = as->ez;
+	unsigned cnt;
+
+printk(KERN_DEBUG "ezusb: async_completed: status %d rval %d\n", status, rval);
+	as->completed.length = rval;
+	if (as->numframes > 0) {
+		as->completed.status = USB_ST_NOERROR;
+		for (cnt = 0; cnt < as->numframes; cnt++) {
+			as->completed.isostat[cnt].status = as->desc.iso->frames[cnt].frame_status;
+			as->completed.isostat[cnt].length = as->desc.iso->frames[cnt].frame_length;
+		}
+	} else
+		as->completed.status = status;
+	spin_lock(&ez->lock);
+	list_del(&as->asynclist);
+	list_add_tail(&as->asynclist, &ez->async_completed);
+	spin_unlock(&ez->lock);
+	wake_up(&ez->wait);
+	return 0;
+}
+
+static void remove_async(struct async *as)
+{
+	if (as->data && as->dataorder)
+		free_pages((unsigned long)as->data, as->dataorder);
+	if (as->numframes)
+		usb_free_isoc(as->desc.iso);
+	kfree(as);
+}
+
+static void kill_async(struct async *as)
+{
+	struct ezusb *ez = as->ez;
+
+	if (as->numframes)
+		/* ISO case */
+		usb_kill_isoc(as->desc.iso);
+	else
+		usb_terminate_bulk(ez->usbdev, as->desc.bulk);
+	as->completed.status = USB_ST_REMOVED;
+	async_movetocompleted(as);
+}
+
+static void destroy_all_async(struct ezusb *ez)
+{
+	struct async *as;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ez->lock, flags);
+	if (!list_empty(&ez->async_pending)) {
+		as = list_entry(ez->async_pending.next, struct async, asynclist);
+		list_del(&as->asynclist);
+		INIT_LIST_HEAD(&as->asynclist);
+		spin_unlock_irqrestore(&ez->lock, flags);
+		kill_async(as);
+		spin_lock_irqsave(&ez->lock, flags);
+	}
+	spin_unlock_irqrestore(&ez->lock, flags);
+	while ((as = async_getcompleted(ez)))
+		remove_async(as);
+}
 
 /* --------------------------------------------------------------------- */
 
@@ -216,439 +383,505 @@
 	up(&ez->mutex);
 	file->f_pos = 0;
 	file->private_data = ez;
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int ezusb_release(struct inode *inode, struct file *file)
 {
 	struct ezusb *ez = (struct ezusb *)file->private_data;
+
+	down(&ez->mutex);
+	destroy_all_async(ez);
+	up(&ez->mutex);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype,
+			 unsigned char request, unsigned short value, 
+			 unsigned short index, unsigned short length,
+			 void *data)
+{
+	unsigned char *tbuf = NULL;
+	unsigned int pipe;
+	int i;
+
+	if (length > PAGE_SIZE)
+		return -EINVAL;
+	/* __range_ok is broken; 
+	   with unsigned short size, it gave
+	   addl %si,%edx ; sbbl %ecx,%ecx; cmpl %edx,12(%eax); sbbl $0,%ecx
+	*/
+	if (requesttype & 0x80) {
+		pipe = usb_rcvctrlpipe(usbdev, 0);
+		if (length > 0 && !access_ok(VERIFY_WRITE, data, (unsigned int)length))
+			return -EFAULT;
+	} else
+		pipe = usb_sndctrlpipe(usbdev, 0);
+	if (length > 0) {
+		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		if (!(requesttype & 0x80)) {
+			if (copy_from_user(tbuf, data, length)) {
+				free_page((unsigned long)tbuf);
+				return -EFAULT;
+			}
+		}
+	}
+	i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length);
+	if (i < 0) {
+		if (length > 0)
+			free_page((unsigned long)tbuf);
+		printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", 
+		       requesttype, request, length, i);
+		return -ENXIO;
+	}
+	if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length))
+		i = -EFAULT;
+	if (length > 0)
+		free_page((unsigned long)tbuf);
+	return i;
+}
+
+static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, void *data)
+{
+	unsigned char *tbuf = NULL;
+	unsigned int pipe;
+	unsigned long len2 = 0;
+	int ret = 0;
+
+	if (length > PAGE_SIZE)
+		return -EINVAL;
+	if ((ep & ~0x80) >= 16)
+		return -EINVAL;
+	if (ep & 0x80) {
+		pipe = usb_rcvbulkpipe(usbdev, ep & 0x7f);
+		if (length > 0 && !access_ok(VERIFY_WRITE, data, length))
+			return -EFAULT;
+	} else
+		pipe = usb_sndbulkpipe(usbdev, ep & 0x7f);
+	if (!usb_maxpacket(usbdev, pipe, !(ep & 0x80)))
+		return -EINVAL;
+	if (length > 0) {
+		if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
+			return -ENOMEM;
+		if (!(ep & 0x80)) {
+			if (copy_from_user(tbuf, data, length)) {
+				free_page((unsigned long)tbuf);
+				return -EFAULT;
+			}
+		}
+	}
+	ret = usbdev->bus->op->bulk_msg(usbdev, pipe, tbuf, length, &len2);
+	if (ret < 0) {
+		if (length > 0)
+			free_page((unsigned long)tbuf);
+		printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", 
+		       ep, length, ret);
+		return -ENXIO;
+	}
+	if (len2 > length)
+		len2 = length;
+	ret = len2;
+	if (ep & 0x80 && len2 > 0 && copy_to_user(data, tbuf, len2))
+		ret = -EFAULT;
+	if (length > 0)
+		free_page((unsigned long)tbuf);
+	return ret;
+}
+
+static int ezusb_resetep(struct usb_device *usbdev, unsigned int ep)
+{
+	if ((ep & ~0x80) >= 16)
+		return -EINVAL;
+	usb_settoggle(usbdev, ep & 0xf, !(ep & 0x80), 0);
 	return 0;
 }
 
-static void iso_schedrcv(struct isodesc *isodesc)
+static int ezusb_setinterface(struct usb_device *usbdev, unsigned int interface, unsigned int altsetting)
 {
-	unsigned diff;
+	if (usb_set_interface(usbdev, interface, altsetting) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config)
+{
+	if (usb_set_configuration(usbdev, config) < 0)
+		return -EINVAL;
+	return 0;
+}
+
+static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab)
+{
+	struct async *as = NULL;
+	unsigned int pipe;
+
+	if (ab->len > PAGE_SIZE)
+		return -EINVAL;
+	if ((ab->ep & ~0x80) >= 16)
+		return -EINVAL;
+	if (ab->ep & 0x80) {
+		pipe = usb_rcvbulkpipe(ez->usbdev, ab->ep & 0x7f);
+		if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len))
+			return -EFAULT;
+	} else
+		pipe = usb_sndbulkpipe(ez->usbdev, ab->ep & 0x7f);
+	if (!usb_maxpacket(ez->usbdev, pipe, !(ab->ep & 0x80)))
+		return -EINVAL;
+	if (!(as = kmalloc(sizeof(struct async), GFP_KERNEL)))
+		return -ENOMEM;
+	INIT_LIST_HEAD(&as->asynclist);
+	as->ez = ez;
+	as->userdata = ab->data;
+	as->numframes = 0;
+	as->data = 0;
+	as->dataorder = 0;
+	as->datalen = ab->len;
+	as->completed.context = ab->context;
+	if (ab->len > 0) {
+		as->dataorder = 1;
+		if (!(as->data = (unsigned char *)__get_free_page(GFP_KERNEL))) {
+			kfree(as);
+			return -ENOMEM;
+		}
+		if (!(ab->ep & 0x80)) {
+			if (copy_from_user(as->data, ab->data, ab->len))
+				goto err_fault;
+			as->datalen = 0; /* no need to copy back at completion */
+		}
+	}
+	async_newpending(as);
+	if (!(as->desc.bulk = usb_request_bulk(ez->usbdev, pipe, async_completed, as->data, ab->len, as))) {
+		async_removelist(as);
+		goto err_inval;
+	}
+	return 0;
 
-	if (!(isodesc->flags & ISOFLG_ACTIVE))
-		return;
-	diff = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-	if (diff < isodesc->framesperint * isodesc->pktsz)
-		return;
-	for (;;) {
-		diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3;
-		if (diff >= 2)
-			return;
-		usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1],
-					 diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL);
-		isodesc->schedcnt++;
-	}
-}
-
-static void iso_schedsnd(struct isodesc *isodesc)
-{
-	unsigned diff, bcnt, x;
-	unsigned char *p1, *p2;
-
-	if (!(isodesc->flags & ISOFLG_ACTIVE))
-		return;
-	for (;;) {
-		diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3;
-		if (diff >= 2)
-			return;
-		bcnt = (isodesc->buflen - isodesc->rd + isodesc->wr) % isodesc->buflen;
-		if (bcnt < isodesc->framesperint * isodesc->pktsz)
-			return;
-		p2 = isodesc->hcbuf[isodesc->schedcnt & 1];
-		for (bcnt = 0; bcnt < isodesc->framesperint; bcnt++) {
-			p1 = isodesc->buf + isodesc->rd;
-			if (isodesc->rd + isodesc->pktsz > isodesc->buflen) {
-				x = isodesc->buflen - isodesc->rd;
-				memcpy(p2, p1, x);
-				memcpy(p2+x, isodesc->buf, isodesc->pktsz - x);
-			} else
-				memcpy(p2, p1, isodesc->pktsz);
-			isodesc->rd = (isodesc->rd + isodesc->pktsz) % isodesc->buflen;
-			p2 += isodesc->pktsz;
-			if (((unsigned long)p2 ^ ((unsigned long)p2 + isodesc->pktsz - 1)) & (~(PAGE_SIZE - 1)))
-				p2 = (void *)(((unsigned long)p2 + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)));
-		}
-		usb_schedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->schedcnt & 1],
-					 diff ? isodesc->hcisodesc[(isodesc->schedcnt - 1) & 1] : NULL);
-		isodesc->schedcnt++;
-	}
-}
-
-static int ezusb_isorcv_irq(int status, void *__buffer, int __len, void *dev_id)
-{
-	struct isodesc *isodesc = (struct isodesc *)dev_id;
-	unsigned int len, len2;
-	unsigned char *p1;
-
-	spin_lock(&isodesc->lock);
-	usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
-	len = usb_compress_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
-	printk(KERN_DEBUG "ezusb_isorcv_irq: %u bytes recvd\n", len);
-	p1 = isodesc->hcbuf[isodesc->unschedcnt & 1];
-	while (len > 0) {
-		len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-		if (!len2)
-			break;
-		if (isodesc->wr + len2 > isodesc->buflen)
-			len2 = isodesc->buflen - isodesc->wr;
-		if (len2 > len)
-			len2 = len;
-		memcpy(isodesc->buf + isodesc->wr, p1, len2);
-		isodesc->wr = (isodesc->wr + len2) % isodesc->buflen;
-		p1 += len2;
-		len -= len2;
-	}
-	isodesc->unschedcnt++;
-	iso_schedrcv(isodesc);
-	spin_unlock(&isodesc->lock);
-	return 1;
-}
-
-static int ezusb_isosnd_irq(int status, void *__buffer, int len, void *dev_id)
-{
-	struct isodesc *isodesc = (struct isodesc *)dev_id;
-
-	spin_lock(&isodesc->lock);
-	usb_unschedule_isochronous(isodesc->usbdev, isodesc->hcisodesc[isodesc->unschedcnt & 1]);
-	isodesc->unschedcnt++;
-	iso_schedsnd(isodesc);
-	spin_unlock(&isodesc->lock);
-	return 1;
-}
-
-static struct isodesc *findiso(struct ezusb *ez, unsigned int ep)
-{
-	struct list_head *head = &ez->iso;
-	struct list_head *tmp = head->next;
-	struct isodesc *id;
-
-	while (tmp != head) {
-		id = list_entry(tmp, struct isodesc, isolist);
-		if (id->ep == ep)
-			return id;
-		tmp = tmp->next;
+ err_fault:
+	if (as) {
+		if (as->data)
+			free_page((unsigned long)as->data);
+		kfree(as);
 	}
-	return NULL;
+	return -EFAULT;
+
+ err_inval:
+	if (as) {
+		if (as->data)
+			free_page((unsigned long)as->data);
+		kfree(as);
+	}
+	return -EINVAL;
+}
+
+static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigned char *cmd)
+{
+	struct async *as;
+	unsigned int maxpkt, pipe;
+	unsigned int dsize, order, assize, j;
+	int i;
+
+	if ((ai->ep & ~0x80) >= 16 || ai->framecnt < 1 || ai->framecnt > 128)
+		return -EINVAL;
+	if (ai->ep & 0x80)
+		pipe = usb_rcvisocpipe(ez->usbdev, ai->ep & 0x7f);
+	else
+		pipe = usb_sndisocpipe(ez->usbdev, ai->ep & 0x7f);
+	if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80))))
+		return -EINVAL;
+	dsize = maxpkt * ai->framecnt;
+	if (dsize > 65536) 
+		return -EINVAL;
+	order = ld2(dsize >> PAGE_SHIFT);
+	if (dsize > (PAGE_SIZE << order))
+		order++;
+	if (ai->ep & 0x80)
+		if (dsize > 0 && !access_ok(VERIFY_WRITE, ai->data, dsize))
+			return -EFAULT;
+	assize = sizeof(struct async) + ai->framecnt * sizeof(struct ezusb_isoframestat);
+	if (!(as = kmalloc(assize, GFP_KERNEL)))
+		return -ENOMEM;
+	memset(as, 0, assize);
+	INIT_LIST_HEAD(&as->asynclist);
+	as->ez = ez;
+	as->userdata = ai->data;
+	as->numframes = ai->framecnt;
+	as->data = 0;
+	as->dataorder = order;
+	as->datalen = dsize;
+	as->completed.context = ai->context;
+	as->desc.iso = NULL;
+	if (dsize > 0) {
+		if (!(as->data = (unsigned char *)__get_free_pages(GFP_KERNEL, order))) {
+			kfree(as);
+			return -ENOMEM;
+		}
+		if (!(ai->ep & 0x80)) {
+			if (copy_from_user(as->data, ai->data, dsize))
+				goto err_fault;
+			as->datalen = 0; /* no need to copy back at completion */
+		}
+	}
+	if ((i = usb_init_isoc(ez->usbdev, pipe, ai->framecnt, as, &as->desc.iso))) {
+		printk(KERN_DEBUG "ezusb: usb_init_isoc error %d\n", i);
+		goto err_inval;
+	}
+	as->desc.iso->start_type = START_ABSOLUTE;
+	as->desc.iso->start_frame = ai->startframe;
+	as->desc.iso->callback_frames = 0;
+	as->desc.iso->callback_fn = async_completed;
+	as->desc.iso->data = as->data;
+	as->desc.iso->buf_size = dsize;
+	for (j = 0; j < ai->framecnt; j++) {
+		if (get_user(i, (int *)(cmd + j * sizeof(struct ezusb_isoframestat)))) {
+			usb_free_isoc(as->desc.iso);
+			kfree(as);
+			return -EFAULT;
+		}
+		if (i < 0)
+			i = 0;
+		as->desc.iso->frames[j].frame_length = i;
+	}
+       	async_newpending(as);
+	if ((i = usb_run_isoc(as->desc.iso, NULL))) {
+		printk(KERN_DEBUG "ezusb: usb_run_isoc error %d\n", i);
+		async_removelist(as);
+		goto err_inval;
+	}
+	return 0;
+
+ err_fault:
+	if (as) {
+		if (as->desc.iso)
+			usb_free_isoc(as->desc.iso);
+		if (as->data)
+			free_page((unsigned long)as->data);
+		kfree(as);
+	}
+	return -EFAULT;
+
+ err_inval:
+	if (as) {
+		if (as->desc.iso)
+			usb_free_isoc(as->desc.iso);
+		if (as->data)
+			free_page((unsigned long)as->data);
+		kfree(as);
+	}
+	return -EINVAL;
+}
+
+static int ezusb_terminateasync(struct ezusb *ez, void *context)
+{
+	struct async *as;
+	int ret = 0;
+
+	while ((as = async_getpending(ez, context))) {
+		kill_async(as);
+		ret++;
+	}
+	return ret;
+}
+
+static int ezusb_asynccompl(struct async *as, void *arg)
+{
+	if (as->datalen > 0) {
+		if (copy_to_user(as->userdata, as->data, as->datalen)) {
+			remove_async(as);
+			return -EFAULT;
+		}
+	}
+	if (copy_to_user(arg, &as->completed, 
+			 sizeof(struct ezusb_asynccompleted) + 
+			 as->numframes * sizeof(struct ezusb_isoframestat))) {
+		remove_async(as);
+		return -EFAULT;
+	}
+	remove_async(as);
+	return 0;
 }
 
 static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct ezusb *ez = (struct ezusb *)file->private_data;
+        DECLARE_WAITQUEUE(wait, current);
+	struct usb_proc_ctrltransfer pctrl;
+	struct usb_proc_bulktransfer pbulk;
+	struct usb_proc_setinterface psetintf;
 	struct ezusb_ctrltransfer ctrl;
 	struct ezusb_bulktransfer bulk;
 	struct ezusb_setinterface setintf;
-	unsigned int len1, ep, pipe, cnt;
-	unsigned long len2;
-	unsigned char tbuf[1024];
-	int i;
-	struct ezusb_isotransfer isot;
-	struct ezusb_isodata isod;
-	struct isodesc *isodesc;
-	usb_device_irq isocompl;
-	unsigned long flags;
-	unsigned char *p1, *p2;
+	struct ezusb_asyncbulk abulk;
+	struct ezusb_asynciso aiso;
+	struct async *as;
+	void *context;
+	unsigned int ep, cfg;
+	int i, ret = 0;
 
+	down(&ez->mutex);
+	if (!ez->usbdev) {
+		up(&ez->mutex);
+		return -EIO;
+	}
 	switch (cmd) {
-	case EZUSB_CONTROL:
-		copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
-		if (ctrl.dlen > sizeof(tbuf) || ctrl.dlen > 1024)
-			return -EINVAL;
-		if (ctrl.requesttype & 0x80) {
-			if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen))
-				return -EINVAL;
-			down(&ez->mutex);
-			if (!ez->usbdev) {
-				up(&ez->mutex);
-				return -EIO;
-			}
-			i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0),
-							     (devrequest *)&ctrl, tbuf, ctrl.dlen);
-			up(&ez->mutex);
-			if (!i && ctrl.dlen) {
-				copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT);
-			}
-		} else {
-			if (ctrl.dlen) {
-				copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT);
-			}
-			down(&ez->mutex);
-			if (!ez->usbdev) {
-				up(&ez->mutex);
-				return -EIO;
-			}
-			i = ez->usbdev->bus->op->control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0),
-							     (devrequest *)&ctrl, tbuf, ctrl.dlen);
-			up(&ez->mutex);
+	case USB_PROC_CONTROL:
+		if (copy_from_user(&pctrl, (void *)arg, sizeof(pctrl))) {
+			ret = -EFAULT;
+			break;
 		}
-		if (i) {
-			printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", 
-			       ctrl.requesttype, ctrl.request, ctrl.length, i);
-			return -ENXIO;
+		ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request, 
+				    pctrl.value, pctrl.index, pctrl.length, pctrl.data);
+		break;
+
+	case USB_PROC_BULK:
+		if (copy_from_user(&pbulk, (void *)arg, sizeof(pbulk))) {
+			ret = -EFAULT;
+			break;
 		}
-		return 0;
+		ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, pbulk.data);
+		break;
 
-	case EZUSB_BULK:
-		copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
-		if (bulk.ep & 0x80)
-			pipe = usb_rcvbulkpipe(ez->usbdev, bulk.ep & 0x7f);
-		else
-			pipe = usb_sndbulkpipe(ez->usbdev, bulk.ep & 0x7f);
-		if (!usb_maxpacket(ez->usbdev, pipe, !(bulk.ep & 0x80)))
-			return -EINVAL;
-		len1 = bulk.len;
-		if (len1 > sizeof(tbuf))
-			len1 = sizeof(tbuf);
-		if (bulk.ep & 0x80) {
-			if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1))
-				return -EINVAL;
-			down(&ez->mutex);
-			if (!ez->usbdev) {
-				up(&ez->mutex);
-				return -EIO;
-			}
-			i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2);
-			up(&ez->mutex);
-			if (!i && len2) {
-				copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
-			}
-		} else {
-			if (len1) {
-				copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
-			}
-			down(&ez->mutex);
-			if (!ez->usbdev) {
-				up(&ez->mutex);
-				return -EIO;
-			}
-			i = ez->usbdev->bus->op->bulk_msg(ez->usbdev, pipe, tbuf, len1, &len2);
-			up(&ez->mutex);
+	case USB_PROC_RESETEP:
+		if (get_user(ep, (unsigned int *)arg)) {
+			ret = -EFAULT;
+			break;
 		}
-		if (i) {
-			printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", 
-			       bulk.ep, bulk.len, i);
-			return -ENXIO;
+		ret = ezusb_resetep(ez->usbdev, ep);
+		break;
+	
+	case USB_PROC_SETINTERFACE:
+		if (copy_from_user(&psetintf, (void *)arg, sizeof(psetintf))) {
+			ret = -EFAULT;
+			break;
 		}
-		return len2;
+		ret = ezusb_setinterface(ez->usbdev, psetintf.interface, psetintf.altsetting);
+		break;
 
-	case EZUSB_RESETEP:
-		get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-		if ((ep & ~0x80) >= 16)
-			return -EINVAL;
-		usb_settoggle(ez->usbdev, ep & 0xf, !(ep & 0x80), 0);
-		return 0;
+	case USB_PROC_SETCONFIGURATION:
+		if (get_user(cfg, (unsigned int *)arg)) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = ezusb_setconfiguration(ez->usbdev, cfg);
+		break;
 
-	case EZUSB_SETINTERFACE:
-		copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT);
-		if (usb_set_interface(ez->usbdev, setintf.interface, setintf.altsetting))
-			return -EINVAL;
-		return 0;
-
-	case EZUSB_STARTISO:
-		copy_from_user_ret(&isot, (void *)arg, sizeof(isot), -EFAULT);
-		len1 = isot.framesperint * isot.pktsz;
-		if (len1 > PAGE_SIZE) {
-			len1 = PAGE_SIZE / isot.pktsz;
-			len1 = PAGE_SIZE * ((isot.framesperint + len1 - 1) / len1);
-		}
-		len2 = (isot.pktsz * 1000 + PAGE_SIZE - 1) & (PAGE_SIZE-1);
-		if (len2 > 32*PAGE_SIZE)
-			len2 = PAGE_SIZE;
-		if ((isot.ep & ~0x80) >= 16 || isot.pktsz < 1 || isot.pktsz > 1023 ||
-		    isot.framesperint < 1 || isot.framesperint > 1000 ||
-		    len1 > 4*PAGE_SIZE)
-			return -EINVAL;
-		down(&ez->mutex);
-		if (!ez->usbdev) {
-			up(&ez->mutex);
-			return -EIO;
+	case EZUSB_CONTROL:
+		if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) {
+			ret = -EFAULT;
+			break;
 		}
-		if (findiso(ez, isod.ep)) {
-			up(&ez->mutex);
-			return -EBUSY;
+		if (ctrl.dlen != ctrl.length) {
+			ret = -EINVAL;
+			break;
 		}
-		if (isot.ep & 0x80) {
-			pipe = usb_rcvisocpipe(ez->usbdev, isot.ep & 15);
-			isocompl = ezusb_isorcv_irq;
-		} else {
-			pipe = usb_sndisocpipe(ez->usbdev, isot.ep & 15);
-			isocompl = ezusb_isosnd_irq;
+		ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request, 
+				    ctrl.value, ctrl.index, ctrl.length, ctrl.data);
+		break;
+
+	case EZUSB_BULK:
+		if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) {
+			ret = -EFAULT;
+			break;
 		}
-		if (!(isodesc = kmalloc(sizeof(struct isodesc), GFP_KERNEL))) {
-			up(&ez->mutex);
-			return -ENOMEM;
+		ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, bulk.data);
+		break;
+
+	case EZUSB_RESETEP:
+		if (get_user(ep, (unsigned int *)arg)) {
+			ret = -EFAULT;
+			break;
 		}
-		memset(isodesc, 0, sizeof(struct isodesc));
-		INIT_LIST_HEAD(&isodesc->isolist);
-		spin_lock_init(&isodesc->lock);
-		isodesc->usbdev = ez->usbdev;
-		isodesc->ep = isot.ep;
-		isodesc->pktsz = isot.pktsz;
-		isodesc->framesperint = isot.framesperint;
-		isodesc->buflen = len2;
-		if (!(isodesc->hcbuf[0] = kmalloc(len1, GFP_KERNEL)) ||
-		    !(isodesc->hcbuf[1] = kmalloc(len1, GFP_KERNEL)))
-			goto startisomemerr;
-		if (!(isodesc->hcisodesc[0] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[0],
-								       len1, isodesc->pktsz, isocompl, isodesc)) ||
-		    !(isodesc->hcisodesc[1] = usb_allocate_isochronous(ez->usbdev, pipe, isodesc->hcbuf[1],
-								       len1, isodesc->pktsz, isocompl, isodesc)))
-			goto startisomemerr;
-		if (!(isodesc->buf = vmalloc(isodesc->buflen)))
-			goto startisomemerr;
-		up(&ez->mutex);
-		return 0;
+		ret = ezusb_resetep(ez->usbdev, ep);
+		break;
+	
+	case EZUSB_SETINTERFACE:
+		if (copy_from_user(&setintf, (void *)arg, sizeof(setintf))) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = ezusb_setinterface(ez->usbdev, setintf.interface, setintf.altsetting);
+		break;
 
-	startisomemerr:
-		if (isodesc->hcisodesc[0])
-			usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
-		if (isodesc->hcisodesc[1])
-			usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
-		if (isodesc->hcbuf[0])
-			kfree(isodesc->hcbuf[0]);
-		if (isodesc->hcbuf[1])
-			kfree(isodesc->hcbuf[1]);
-		if (isodesc->buf)
-			vfree(isodesc->buf);
-		up(&ez->mutex);
-		return -ENOMEM;
+	case EZUSB_SETCONFIGURATION:
+		if (get_user(cfg, (unsigned int *)arg)) {
+			ret = -EFAULT;
+			break;
+		}
+		ret = ezusb_setconfiguration(ez->usbdev, cfg);
+		break;
 
-	case EZUSB_STOPISO:
-		get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-		if ((ep & ~0x80) >= 16)
-			return -EINVAL;
-		down(&ez->mutex);
-		if (!ez->usbdev) {
+	case EZUSB_ASYNCCOMPLETED:
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&ez->wait, &wait);
+		for (;;) {
+			if (!ez->usbdev)
+				break;
+			if ((as = async_getcompleted(ez)))
+				break;
+			if (signal_pending(current))
+				break;
 			up(&ez->mutex);
-			return -EIO;
+			schedule();
+			down(&ez->mutex);
 		}
-		if (!(isodesc = findiso(ez, ep))) {
-			up(&ez->mutex);
-			return -EINVAL;
+		remove_wait_queue(&ez->wait, &wait);
+		current->state = TASK_RUNNING;
+		if (as) {
+			ret = ezusb_asynccompl(as, (void *)arg);
+			break;
 		}
-		list_del(&isodesc->isolist);
-		usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
-		usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
-		kfree(isodesc->hcbuf[0]);
-		kfree(isodesc->hcbuf[1]);
-		vfree(isodesc->buf);
-		up(&ez->mutex);
-		return 0;
-
-	case EZUSB_ISODATA:
-		copy_from_user_ret(&isod, (void *)arg, sizeof(isod), -EFAULT);
-		if ((isod.ep & ~0x80) >= 16)
-			return -EINVAL;
-		if (isod.size)
-			if (!access_ok((isod.ep & 0x80) ? VERIFY_WRITE : VERIFY_READ, isod.data, isod.size))
-				return -EFAULT;
-		down(&ez->mutex);
-		if (!ez->usbdev) {
-			up(&ez->mutex);
-			return -EIO;
+		if (signal_pending(current)) {
+			ret = -EINTR;
+			break;
 		}
-		if (!(isodesc = findiso(ez, ep))) {
-			up(&ez->mutex);
-			return -EINVAL;
+		ret = -EIO;
+		break;
+
+	case EZUSB_ASYNCCOMPLETEDNB:
+		if ((as = async_getcompleted(ez))) {
+			ret = ezusb_asynccompl(as, (void *)arg);
+			break;
 		}
-		if (isod.ep & 0x80) {
-			cnt = 0;
-			p1 = isod.data;
-			while (cnt < isod.size) {
-				spin_lock_irqsave(&isodesc->lock, flags);
-				p2 = isodesc->buf + isodesc->rd;
-				len2 = (isodesc->rd >= isodesc->wr) ? isodesc->buflen : isodesc->wr;
-				len2 -= isodesc->rd;
-				spin_unlock_irqrestore(&isodesc->lock, flags);
-				if (len2 <= 0)
-					break;
-				if (len2 >= isod.size - cnt)
-					len2 = isod.size - cnt;
-				if (__copy_to_user(p1, p2, len2)) {
-					up(&ez->mutex);
-					return -EFAULT;
-				}
-				p1 += len2;
-				cnt += len2;
-				spin_lock_irqsave(&isodesc->lock, flags);
-				isodesc->rd = (isodesc->rd + len2) % isodesc->buflen;
-				spin_unlock_irqrestore(&isodesc->lock, flags);
-			}
-			isod.size = cnt;
-			iso_schedrcv(isodesc);
-		} else {
-			cnt = 0;
-			p1 = isod.data;
-			while (cnt < isod.size) {
-				spin_lock_irqsave(&isodesc->lock, flags);
-				p2 = isodesc->buf + isodesc->wr;
-				len2 = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-				if (isodesc->wr + len2 > isodesc->buflen)
-					len2 = isodesc->buflen - isodesc->wr;
-				spin_unlock_irqrestore(&isodesc->lock, flags);
-				if (len2 <= 0)
-					break;
-				if (len2 >= isod.size - cnt)
-					len2 = isod.size - cnt;
-				if (__copy_from_user(p2, p1, len2)) {
-					up(&ez->mutex);
-					return -EFAULT;
-				}
-				p1 += len2;
-				cnt += len2;
-				spin_lock_irqsave(&isodesc->lock, flags);
-				isodesc->wr = (isodesc->wr + len2) % isodesc->buflen;
-				spin_unlock_irqrestore(&isodesc->lock, flags);
-			}
-			isod.size = cnt;
-			iso_schedsnd(isodesc);
+		ret = -EAGAIN;
+		break;
+
+	case EZUSB_REQUESTBULK:
+		if (copy_from_user(&abulk, (void *)arg, sizeof(abulk))) {
+			ret = -EFAULT;
+			break;
 		}
-		spin_lock_irqsave(&isodesc->lock, flags);
-		isod.bufqueued = (isodesc->buflen + isodesc->wr - isodesc->rd) % isodesc->buflen;
-		isod.buffree = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen;
-		spin_unlock_irqrestore(&isodesc->lock, flags);
-		up(&ez->mutex);
-		copy_to_user_ret((void *)arg, &isod, sizeof(isod), -EFAULT);
-		return 0;
+		ret = ezusb_requestbulk(ez, &abulk);
+		break;	
 
-	case EZUSB_PAUSEISO:
-		get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-		if ((ep & ~0x80) >= 16)
-			return -EINVAL;
-		if (!(isodesc = findiso(ez, ep)))
-			return -EINVAL;
-		spin_lock_irqsave(&isodesc->lock, flags);
-		isodesc->flags &= ~ISOFLG_ACTIVE;
-		spin_unlock_irqrestore(&isodesc->lock, flags);
-		return 0;
-
-	case EZUSB_RESUMEISO:
-		get_user_ret(ep, (unsigned int *)arg, -EFAULT);
-		if ((ep & ~0x80) >= 16)
-			return -EINVAL;
-		down(&ez->mutex);
-		if (!ez->usbdev) {
-			up(&ez->mutex);
-			return -EIO;
+	case EZUSB_REQUESTISO:
+		if (copy_from_user(&aiso, (void *)arg, sizeof(aiso))) {
+			ret = -EFAULT;
+			break;
 		}
-		if (!(isodesc = findiso(ez, ep))) {
-			up(&ez->mutex);
-			return -EINVAL;
+		ret = ezusb_requestiso(ez, &aiso, ((unsigned char *)arg)+sizeof(aiso));
+		break;
+
+	case EZUSB_TERMINATEASYNC:
+		if (get_user(context, (void **)arg)) {
+			ret = -EFAULT;
+			break;
 		}
-		spin_lock_irqsave(&isodesc->lock, flags);
-		isodesc->flags |= ISOFLG_ACTIVE;
-		if (isot.ep & 0x80)
-			iso_schedrcv(isodesc);
-		else
-			iso_schedsnd(isodesc);
-		spin_unlock_irqrestore(&isodesc->lock, flags);
-		up(&ez->mutex);
-		return 0;
+		ret = ezusb_terminateasync(ez, context);
+		break;
+
+	case EZUSB_GETFRAMENUMBER:
+		i = usb_get_current_frame_number(ez->usbdev);
+		ret = put_user(i, (int *)arg);
+		break;
+
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
 	}
-	return -ENOIOCTLCMD;
+	up(&ez->mutex);
+	return ret;
 }
 
 static struct file_operations ezusb_fops = {
@@ -707,12 +940,12 @@
 	}
 	ez->usbdev = usbdev;
 	usbdev->private = ez;
-        if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue)) {
+        if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue) < 0) {
 		printk(KERN_ERR "ezusb: set_configuration failed\n");
 		goto err;
 	}
         interface = &usbdev->config[0].interface[0].altsetting[1];
-	if (usb_set_interface(usbdev, 0, 1)) {
+	if (usb_set_interface(usbdev, 0, 1) < 0) {
 		printk(KERN_ERR "ezusb: set_interface failed\n");
 		goto err;
 	}
@@ -730,20 +963,12 @@
 static void ezusb_disconnect(struct usb_device *usbdev)
 {
 	struct ezusb *ez = (struct ezusb *)usbdev->private;
-	struct isodesc *isodesc;
 
 	down(&ez->mutex);
-	while (!list_empty(&ez->iso)) {
-		isodesc = list_entry(ez->iso.next, struct isodesc, isolist);
-		list_del(ez->iso.next);
-		usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[0]);
-		usb_delete_isochronous(ez->usbdev, isodesc->hcisodesc[1]);
-		kfree(isodesc->hcbuf[0]);
-		kfree(isodesc->hcbuf[1]);
-		vfree(isodesc->buf);
-	}
+	destroy_all_async(ez);
 	ez->usbdev = NULL;
 	up(&ez->mutex);
+	wake_up(&ez->wait);
         usbdev->private = NULL;
 	MOD_DEC_USE_COUNT;
 }
@@ -765,7 +990,10 @@
 	for (u = 0; u < NREZUSB; u++) {
 		init_MUTEX(&ezusb[u].mutex);
 		ezusb[u].usbdev = NULL;
-		INIT_LIST_HEAD(&ezusb[u].iso);
+		INIT_LIST_HEAD(&ezusb[u].async_pending);
+		INIT_LIST_HEAD(&ezusb[u].async_completed);
+		init_waitqueue_head(&ezusb[u].wait);
+		spin_lock_init(&ezusb[u].lock);
 	}
 	/* register misc device */
 	if (misc_register(&ezusb_misc)) {
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/ezusb.h linux/drivers/usb/ezusb.h
--- v2.3.16/linux/drivers/usb/ezusb.h	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/ezusb.h	Tue Sep  7 10:19:45 1999
@@ -43,45 +43,58 @@
 	void *data;
 };
 
-#define EZUSB_CONTROL        _IOWR('E', 0, struct ezusb_ctrltransfer)
-
 struct ezusb_bulktransfer {
 	unsigned int ep;
 	unsigned int len;
 	void *data;
 };
 
-#define EZUSB_BULK           _IOWR('E', 2, struct ezusb_bulktransfer)
-
-#define EZUSB_RESETEP        _IOR('E', 3, unsigned int)
-
 struct ezusb_setinterface {
 	unsigned int interface;
 	unsigned int altsetting;
 };
 
-#define EZUSB_SETINTERFACE   _IOR('E', 4, struct ezusb_setinterface)
+struct ezusb_isoframestat {
+	unsigned int length;
+	unsigned int status;
+};
+
+struct ezusb_asynccompleted {
+	int status;
+	unsigned length;
+	void *context;
+	struct ezusb_isoframestat isostat[0];
+};
 
-struct ezusb_isotransfer {
+struct ezusb_asyncbulk {
 	unsigned int ep;
-	unsigned int pktsz;
-	unsigned int framesperint;
+	unsigned int len;
+	void *context;
+	void *data;
 };
 
-struct ezusb_isodata {
+struct ezusb_asynciso {
 	unsigned int ep;
-	unsigned int size;
-	unsigned int bufqueued;
-	unsigned int buffree;
+	
+	unsigned int framecnt;
+	unsigned int startframe;
+
+	void *context;
 	void *data;
+	struct ezusb_isoframestat isostat[0];
 };
 
-#define EZUSB_STARTISO		_IOR('E', 8, struct ezusb_isotransfer)
-#define EZUSB_STOPISO		_IOR('E', 9, unsigned int)
-#define EZUSB_ISODATA		_IOWR('E', 10, struct ezusb_isodata)
-#define EZUSB_PAUSEISO		_IOR('E', 11, unsigned int)
-#define EZUSB_RESUMEISO		_IOR('E', 12, unsigned int)
+#define EZUSB_CONTROL           _IOWR('E', 0, struct ezusb_ctrltransfer)
+#define EZUSB_BULK              _IOWR('E', 2, struct ezusb_bulktransfer)
+#define EZUSB_RESETEP           _IOR('E', 3, unsigned int)
+#define EZUSB_SETINTERFACE      _IOR('E', 4, struct ezusb_setinterface)
+#define EZUSB_SETCONFIGURATION  _IOR('E', 5, unsigned int)
+#define EZUSB_ASYNCCOMPLETED    _IOW('E', 8, struct ezusb_asynccompleted)
+#define EZUSB_ASYNCCOMPLETEDNB  _IOW('E', 9, struct ezusb_asynccompleted)
+#define EZUSB_REQUESTBULK       _IOR('E', 16, struct ezusb_asyncbulk)
+#define EZUSB_REQUESTISO        _IOR('E', 17, struct ezusb_asynciso)
+#define EZUSB_TERMINATEASYNC    _IOR('E', 18, void *)
+#define EZUSB_GETFRAMENUMBER    _IOW('E', 18, unsigned int)
 
 /* --------------------------------------------------------------------- */
 #endif /* _LINUX_EZUSB_H */
-
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/hp_scanner.c linux/drivers/usb/hp_scanner.c
--- v2.3.16/linux/drivers/usb/hp_scanner.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hp_scanner.c	Wed Sep  1 15:31:47 1999
@@ -0,0 +1,344 @@
+/* -*- linux-c -*- */
+
+/* 
+ * Driver for USB HP Scanners
+ *
+ * David E. Nelson (dnelson@jump.net)
+ * 
+ * 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.
+ *
+ * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
+ *
+ * History
+ *  0.1  8/31/1999
+ *
+ *    Developed/tested using linux-2.3.15 with minor ohci.c changes to
+ *    support short packes during bulk xfer mode.  Some testing was
+ *    done with ohci-hcd but the performace was low.  Very limited
+ *    testing was performed with uhci but I was unable to get it to
+ *    work.  Initial relase to the linux-usb development effort.
+ *
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+/* stall/wait timeout for scanner */
+#define NAK_TIMEOUT (HZ)
+
+/* For some reason, an IBUF_SIZE of 8192 causes REALLY big problems
+ * with linux-2.3.15.  Anything more than 4k seems to not have an
+ * effect on increasing performance. Anything smaller than 4k hurts
+ * it.  */
+#define IBUF_SIZE 4096
+
+/* This is a scanner, so not much data is sent to it.  The largest
+ * stuff may be some kind of maps and stuff but that's kinda rare.  */
+#define OBUF_SIZE 128
+
+#define USB_SCANNER_MAJOR 16
+
+struct hpscan_usb_data {
+	struct usb_device 	*hpscan_dev;            /* init: probe_scanner */
+	__u8			isopen;			/* nz if open */
+
+	__u8                    present;                /* Device is present on the bus */
+	char			*obuf;			/* transfer buffers */
+	char			*ibuf;		
+	wait_queue_head_t	wait_q;			/* for timeouts */
+};
+
+static struct hpscan_usb_data hpscan;
+
+static int
+open_scanner(struct inode * inode, struct file * file)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	if (hps->isopen) {
+		return -EBUSY;
+	}
+	hps->isopen = 1;
+
+	init_waitqueue_head(&hps->wait_q);
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static int
+close_scanner(struct inode * inode, struct file * file)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	hps->isopen = 0;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static ssize_t
+write_scanner(struct file * file, const char * buffer,
+              size_t count, loff_t *ppos)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	unsigned long copy_size;
+	unsigned long bytes_written = 0;
+	unsigned long partial;
+
+	int result = 0;
+	int maxretry;
+	
+	do {
+		unsigned long thistime;
+		char *obuf = hps->obuf;
+
+		thistime = copy_size = (count > OBUF_SIZE) ?  OBUF_SIZE : count;
+		if (copy_from_user(hps->obuf, buffer, copy_size))
+			return -EFAULT;
+		maxretry = 5;
+		while (thistime) {
+			if (!hps->hpscan_dev)
+				return -ENODEV;
+			if (signal_pending(current)) {
+				return bytes_written ? bytes_written : -EINTR;
+			}
+
+			result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev,usb_sndbulkpipe(hps->hpscan_dev, 2), obuf, thistime, &partial);
+			
+			//printk(KERN_DEBUG "write stats: result:%d thistime:%lu partial:%lu\n", result, thistime, partial);
+
+			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
+				if(!maxretry--) {
+					return -ETIME;
+				}
+				interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
+				continue;
+			} else if (!result & partial) {
+				obuf += partial;
+				thistime -= partial;
+			} else
+				break;
+		};
+		if (result) {
+			printk("Write Whoops - %x\n", result);
+			return -EIO;
+		}
+		bytes_written += copy_size;
+		count -= copy_size;
+		buffer += copy_size;
+	} while ( count > 0 );
+	
+	return bytes_written ? bytes_written : -EIO;
+}
+
+static ssize_t
+read_scanner(struct file * file, char * buffer,
+             size_t count, loff_t *ppos)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	ssize_t read_count;
+
+	unsigned long partial;
+
+	int this_read;
+	int result;
+
+/* Wait for the scanner to get it's act together.  This may involve
+ * resetting the head, warming up the lamp, etc.  maxretry is number
+ * of seconds.  */
+	int maxretry = 30; 
+
+	char *ibuf = hps->ibuf;
+
+	read_count = 0;
+
+	while (count) {
+		if (signal_pending(current)) {
+			return read_count ? read_count : -EINTR;
+		}
+		if (!hps->hpscan_dev)
+			return -ENODEV;
+		this_read = (count > IBUF_SIZE) ? IBUF_SIZE : count;
+		
+		result = hps->hpscan_dev->bus->op->bulk_msg(hps->hpscan_dev, usb_rcvbulkpipe(hps->hpscan_dev, 1), ibuf, this_read, &partial);
+
+		printk(KERN_DEBUG "read stats: result:%d this_read:%u partial:%lu\n", result, this_read, partial);
+		
+		if (partial) {
+			count = this_read = partial;
+		} else if (result == USB_ST_TIMEOUT || result == 15) {
+			if(!maxretry--) {
+				printk(KERN_DEBUG "read_scanner: maxretry timeout\n");
+				return -ETIME;
+			}
+			interruptible_sleep_on_timeout(&hps->wait_q, NAK_TIMEOUT);
+			continue;
+		} else if (result != USB_ST_DATAUNDERRUN) {
+			printk("Read Whoops - result:%u partial:%lu this_read:%u\n", result, partial, this_read);
+			return -EIO;
+		} else {
+			return (0);
+		}
+		
+		if (this_read) {
+			if (copy_to_user(buffer, ibuf, this_read))
+				return -EFAULT;
+			count -= this_read;
+			read_count += this_read;
+			buffer += this_read;
+		}
+	}
+	return read_count;
+}
+
+static int
+probe_scanner(struct usb_device *dev)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	/*
+	 * Don't bother using an HP 4200C since it does NOT understand
+	 * SCL and HP isn't going to be releasing the specs any time
+	 * soon.  */
+	if (dev->descriptor.idVendor != 0x3f0 ) {
+		printk(KERN_INFO "Scanner is not an HP Scanner.\n");
+		return -1;
+	}
+
+	if (dev->descriptor.idProduct != 0x101 && /* HP 4100C */
+	    dev->descriptor.idProduct != 0x202 && /* HP 5100C */
+            dev->descriptor.idProduct != 0x601) { /* HP 6300C */
+		printk(KERN_INFO "Scanner model not supported/tested.\n");
+		return -1;
+	}
+	
+	printk(KERN_DEBUG "USB Scanner found at address %d\n", dev->devnum);
+	
+	if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) {
+		printk(KERN_DEBUG "Failed to set configuration\n");
+		return -1;
+	}
+
+	hps->present = 1;
+	hps->hpscan_dev = dev;
+
+	if (!(hps->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+
+	if (!(hps->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
+		return -ENOMEM;
+	}
+  
+	return 0;
+}
+
+static void
+disconnect_scanner(struct usb_device *dev)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	if (hps->isopen) {
+		/* better let it finish - the release will do whats needed */
+		hps->hpscan_dev = NULL;
+		return;
+	}
+	kfree(hps->ibuf);
+	kfree(hps->obuf);
+
+	dev->private = NULL;		/* just in case */
+	hps->present = 0;
+}
+
+static struct
+usb_driver scanner_driver = {
+	"usbscanner",
+	probe_scanner,
+	disconnect_scanner,
+	{ NULL, NULL }
+};
+
+static struct
+file_operations usb_scanner_fops = {
+	NULL,		/* seek */
+	read_scanner,
+	write_scanner,
+	NULL,		/* readdir */
+	NULL,		/* poll */
+	NULL,    	/* ioctl */
+	NULL,		/* mmap */
+	open_scanner,
+	NULL,		/* flush */
+	close_scanner,
+	NULL,         
+	NULL,         /* fasync */
+};
+
+int
+usb_hp_scanner_init(void)
+{
+	int result;
+	
+	if ((result = register_chrdev(USB_SCANNER_MAJOR, "usbscanner", &usb_scanner_fops)) < 0) {
+		printk(KERN_WARNING "hp_scanner: Cannot register device\n");
+		return result;
+	}
+	usb_register(&scanner_driver);
+	printk(KERN_DEBUG "USB Scanner support registered.\n");
+	return 0;
+}
+
+
+void
+usb_hp_scanner_cleanup(void)
+{
+	struct hpscan_usb_data *hps = &hpscan;
+
+	hps->present = 0;
+	usb_deregister(&scanner_driver);
+	unregister_chrdev(USB_SCANNER_MAJOR, "usbscanner");
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	return usb_hp_scanner_init();
+}
+
+void
+cleanup_module(void)
+{
+	usb_hp_scanner_cleanup();
+}
+#endif
+
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.3.16/linux/drivers/usb/inits.h	Tue Jul 27 16:05:50 1999
+++ linux/drivers/usb/inits.h	Wed Sep  1 16:24:19 1999
@@ -5,5 +5,6 @@
 int usb_printer_init(void);
 void usb_hub_cleanup(void);
 void usb_mouse_cleanup(void);
+int usb_scsi_init(void);
 int proc_usb_init (void);
 void proc_usb_cleanup (void);
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.3.16/linux/drivers/usb/mouse.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/mouse.c	Wed Sep  1 16:24:19 1999
@@ -4,6 +4,12 @@
  *
  * Brad Keryan 4/3/1999
  *
+ * version 0.30? Paul Ashton 1999/08/19 - Fixed behaviour on mouse
+ * disconnect and suspend/resume. Added module parameter "force=1"
+ * to allow opening of the mouse driver before mouse has been plugged
+ * in (enables consistent XF86Config settings). Fixed module use count.
+ * Documented missing blocking/non-blocking read handling (not fixed).
+ * 
  * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
  * correctly. Events are added together, not queued, to keep the rodent sober.
  *
@@ -49,6 +55,7 @@
 	int present; /* this mouse is plugged in */
 	int active; /* someone is has this mouse's device open */
 	int ready; /* the mouse has changed state since the last read */
+	int suspended; /* mouse disconnected */
 	wait_queue_head_t wait; /* for polling */
 	struct fasync_struct *fasync;
 	/* later, add a list here to support multiple mice */
@@ -65,12 +72,38 @@
 
 spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
 
+static int force=0; /* allow the USB mouse to be opened even if not there (yet) */
+MODULE_PARM(force,"i");
+
 static int mouse_irq(int state, void *__buffer, int len, void *dev_id)
 {
 	signed char *data = __buffer;
 	/* finding the mouse is easy when there's only one */
 	struct mouse_state *mouse = &static_mouse_state; 
 
+	if (state)
+		printk(KERN_DEBUG "%s(%d):state %d, bp %p, len %d, dp %p\n",
+			__FILE__, __LINE__, state, __buffer, len, dev_id);
+
+	/*
+	 * USB_ST_NOERROR is the normal case.
+	 * USB_ST_REMOVED occurs if mouse disconnected or suspend/resume
+	 * USB_ST_INTERNALERROR occurs if system suspended then mouse removed
+	 *    followed by resume. On UHCI could then occur every second
+	 * In both cases, suspend the mouse
+	 * On other states, ignore
+	 */
+	switch (state) {
+	case USB_ST_REMOVED:
+	case USB_ST_INTERNALERROR: 
+		printk(KERN_DEBUG "%s(%d): Suspending\n",
+			__FILE__, __LINE__);
+		mouse->suspended = 1;
+		return 0; /* disable */
+	case USB_ST_NOERROR: break;
+	default: return 1; /* ignore */
+	}	
+
 	/* if a mouse moves with no one listening, do we care? no */
 	if(!mouse->active)
 		return 1;
@@ -110,9 +143,11 @@
 
 	fasync_mouse(-1, file, 0);
 
+	printk(KERN_DEBUG "%s(%d): MOD_DEC\n", __FILE__, __LINE__);
 	MOD_DEC_USE_COUNT;
 
 	if (--mouse->active == 0) {
+		mouse->suspended = 0;
 		/* stop polling the mouse while its not in use */
 	    	usb_release_irq(mouse->dev, mouse->irq_handle);
 		/* never keep a reference to a released IRQ! */
@@ -126,15 +161,38 @@
 {
 	struct mouse_state *mouse = &static_mouse_state;
 
+	printk(KERN_DEBUG "%s(%d): open_mouse\n", __FILE__, __LINE__);
+	/*
+	 * First open may fail since mouse_probe() may get called after this
+	 * if module load is in response to the open
+	 * mouse_probe() sets mouse->present. This open can be delayed by
+	 * specifying force=1 in module load
+	 * This helps if you want to insert the USB mouse after starting X
+	 */
 	if (!mouse->present)
-		return -EINVAL;
+	{
+		if (force) /* always load the driver even if no mouse (yet) */
+		{
+			printk(KERN_DEBUG "%s(%d): forced open\n",
+				__FILE__, __LINE__);
+			mouse->suspended = 1;
+		}
+		else
+			return -EINVAL;
+	}
+
+	/* prevent the driver from being unloaded while its in use */
+	printk(KERN_DEBUG "%s(%d): MOD_INC\n", __FILE__, __LINE__);
+	/* Increment use count even if already active */
+	MOD_INC_USE_COUNT;
+
 	if (mouse->active++)
 		return 0;
 	/* flush state */
 	mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
 
-	/* prevent the driver from being unloaded while its in use */
-	MOD_INC_USE_COUNT;
+	if (!mouse->present) /* only get here if force == 1 */
+		return 0;
 
 	/* start the usb controller's polling of the mouse */
 	mouse->irq_handle = usb_request_irq(mouse->dev, usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress), mouse_irq, mouse->bInterval, NULL);
@@ -160,6 +218,10 @@
 	static int state = 0;
 	struct mouse_state *mouse = &static_mouse_state;
 
+	/*
+	 * FIXME - Other mouse drivers handle blocking and nonblocking reads
+	 * differently here...
+	 */
 	if (count) {
 		mouse->ready = 0;
 		switch (state) {
@@ -304,6 +366,19 @@
 	mouse->bInterval = endpoint->bInterval;
 
 	mouse->present = 1;
+
+	/* This appears to let USB mouse survive disconnection and */
+	/* APM suspend/resume */
+	if (mouse->suspended)
+	{
+		printk(KERN_DEBUG "%s(%d): mouse resume\n", __FILE__, __LINE__);
+		/* restart the usb controller's polling of the mouse */
+		mouse->irq_handle = usb_request_irq(mouse->dev,
+			usb_rcvctrlpipe(mouse->dev, mouse->bEndpointAddress),
+			mouse_irq, mouse->bInterval, NULL);
+		mouse->suspended = 0;
+	}
+
 	return 0;
 }
 
@@ -315,7 +390,6 @@
 	if (mouse->present) {
 	    	usb_release_irq(mouse->dev, mouse->irq_handle);
 		/* never keep a reference to a released IRQ! */
-		mouse->irq_handle = NULL;
 	}
 
 	mouse->irq_handle = NULL;
@@ -336,7 +410,7 @@
 {
 	struct mouse_state *mouse = &static_mouse_state;
 
-	mouse->present = mouse->active = 0;
+	mouse->present = mouse->active = mouse->suspended = 0;
 	mouse->irq_handle = NULL;
 	init_waitqueue_head(&mouse->wait);
 	mouse->fasync = NULL;
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c
--- v2.3.16/linux/drivers/usb/ohci.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/ohci.c	Wed Sep  1 15:31:47 1999
@@ -1455,7 +1455,7 @@
 
 	return ohci_generic_trans(usb_dev, pipe,
 			TOGGLE_AUTO,
-			1 /* round */, 1 /* autofree */,
+			0 /* round */, 1 /* autofree */,
 			dev_id, handler, data, len,
 			HCD_ED_BULK,
 			NULL /* no setup_td */, NULL /* no status_td */ );
@@ -1504,7 +1504,7 @@
 #endif
 
 	/* only count TDs that were completed successfully */
-	if (stats == USB_ST_NOERROR)
+	if (stats == USB_ST_NOERROR || stats == USB_ST_DATAUNDERRUN) /*DEN*/
 		req->_bytes_done += len;
 
 #ifdef OHCI_DEBUG
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.3.16/linux/drivers/usb/uhci.c	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/uhci.c	Thu Sep  2 10:22:08 1999
@@ -23,6 +23,12 @@
 /* 4/4/1999 added data toggle for interrupt pipes -keryan */
 /* 5/16/1999 added global toggles for bulk and control */
 /* 6/25/1999 added fix for data toggles on bidirectional bulk endpoints */ 
+/*
+ * 1999-09-02: Thomas Sailer <sailer@ife.ee.ethz.ch>
+ *             Added explicit frame list manipulation routines
+ *             for inserting/removing iso td's to/from the frame list.
+ *             START_ABSOLUTE fixes
+ */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -463,6 +469,84 @@
 }
 
 /*
+ * frame list manipulation. Used for Isochronous transfers.
+ * the list of (iso) TD's enqueued in a frame list entry
+ * is basically a doubly linked list with link being
+ * the forward pointer and backptr the backward ptr.
+ * the frame list entry itself doesn't have a back ptr
+ * (therefore the list is not circular), and the forward pointer
+ * stops at link entries having the UHCI_PTR_TERM or the UHCI_PTR_QH
+ * bit set. Maybe it could be extended to handle the QH's also,
+ * but it doesn't seem necessary right now.
+ * The layout looks as follows:
+ * frame list pointer -> iso td's (if any) -> 
+ * periodic interrupt td (if framelist 0) -> irq qh -> control qh -> bulk qh
+ */
+
+static spinlock_t framelist_lock = SPIN_LOCK_UNLOCKED;
+
+static void uhci_add_frame_list(struct uhci *uhci, struct uhci_td *td, unsigned framenum)
+{
+	unsigned long flags;
+	struct uhci_td *nexttd;
+
+	framenum %= UHCI_NUMFRAMES;
+	spin_lock_irqsave(&framelist_lock, flags);
+	td->backptr = &uhci->fl->frame[framenum];
+	td->link = uhci->fl->frame[framenum];
+	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+		nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+		nexttd->backptr = &td->link;
+	}
+	wmb();
+	uhci->fl->frame[framenum] = virt_to_bus(td);
+	spin_unlock_irqrestore(&framelist_lock, flags);
+}
+
+static void uhci_remove_frame_list(struct uhci *uhci, struct uhci_td *td)
+{
+	unsigned long flags;
+	struct uhci_td *nexttd;
+
+	if (!td->backptr)
+		return;
+	spin_lock_irqsave(&framelist_lock, flags);
+	*(td->backptr) = td->link;
+	if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+		nexttd = (struct uhci_td *)bus_to_virt(td->link & ~15);
+		nexttd->backptr = td->backptr;
+	}
+	spin_unlock_irqrestore(&framelist_lock, flags);
+	td->backptr = NULL;
+	/*
+	 * attention: td->link might still be in use by the
+	 * hardware if the td is still active and the hardware
+	 * was processing it. So td->link should be preserved
+	 * until the frame number changes. Don't know what to do...
+	 * udelay(1000) doesn't sound nice, and schedule()
+	 * can't be used as this is called from within interrupt context.
+	 */
+	/* for now warn if there's a possible problem */
+	if (td->status & TD_CTRL_ACTIVE) {
+		unsigned frn = inw(uhci->io_addr + USBFRNUM);
+		__u32 link = uhci->fl->frame[frn % UHCI_NUMFRAMES];
+		if (!(link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
+			struct uhci_td *tdl = (struct uhci_td *)bus_to_virt(link & ~15);
+			for (;;) {
+				if (tdl == td) {
+					printk(KERN_WARNING "uhci_remove_frame_list: td possibly still in use!!\n");
+					break;
+				}
+				if (tdl->link & (UHCI_PTR_TERM | UHCI_PTR_QH))
+					break;
+				tdl = (struct uhci_td *)bus_to_virt(tdl->link & ~15);
+			}
+		}	
+	}
+}
+
+
+/*
  * This function removes and disallocates all structures set up for a transfer.
  * It takes the qh out of the skeleton, removes the tq and the td's.
  * It only removes the associated interrupt handler if removeirq is set.
@@ -619,6 +703,7 @@
 				struct usb_isoc_desc **isocdesc)
 {
 	struct usb_isoc_desc *id;
+	int i;
 
 #ifdef BANDWIDTH_ALLOCATION
 	/* TBD: add bandwidth allocation/checking/management HERE. */
@@ -628,7 +713,7 @@
 	*isocdesc = NULL;
 
 	/* Check some parameters. */
-	if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) {
+	if ((frame_count <= 0) || (frame_count > UHCI_NUMFRAMES)) {
 #ifdef CONFIG_USB_DEBUG_ISOC
 		printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n",
 			frame_count);
@@ -648,16 +733,20 @@
 	if (!id)
 		return -ENOMEM;
 
+	memset (id, 0, sizeof (*id) +
+		(sizeof (struct isoc_frame_desc) * frame_count));
+
 	id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL);
 	if (!id->td) {
 		kfree (id);
 		return -ENOMEM;
 	}
 
-	memset (id, 0, sizeof (*id) +
-		(sizeof (struct isoc_frame_desc) * frame_count));
 	memset (id->td, 0, sizeof (struct uhci_td) * frame_count);
 
+	for (i = 0; i < frame_count; i++)
+		INIT_LIST_HEAD(&((struct uhci_td *)(id->td))[i].irq_list);
+
 	id->frame_count = frame_count;
 	id->frame_size  = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe));
 		/* TBD: or make this a parameter to allow for frame_size
@@ -755,7 +844,7 @@
 	cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev);
 
 	/* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */
-	if (!pr_isocdesc)
+	if (!pr_isocdesc) {
 		if (isocdesc->start_type == START_RELATIVE) {
 			if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > CAN_SCHEDULE_FRAMES)) {
 #ifdef CONFIG_USB_DEBUG_ISOC
@@ -766,9 +855,10 @@
 			}
 		} /* end START_RELATIVE */
 		else
-		if (isocdesc->start_type == START_ABSOLUTE) {
-			if (isocdesc->start_frame > cur_frame) {
-				if ((isocdesc->start_frame - cur_frame) > CAN_SCHEDULE_FRAMES) {
+  		if (isocdesc->start_type == START_ABSOLUTE) { /* within the scope of cur_frame */
+			ix = USB_WRAP_FRAMENR(isocdesc->start_frame - cur_frame);
+			if (ix < START_FRAME_FUDGE || /* too small */
+			    ix > CAN_SCHEDULE_FRAMES) { /* too large */
 #ifdef CONFIG_USB_DEBUG_ISOC
 					printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n",
 						isocdesc->start_frame);
@@ -787,6 +877,7 @@
 				}
 			}
 		} /* end START_ABSOLUTE */
+	}
 
 	/*
 	 * Set the start/end frame numbers.
@@ -800,16 +891,14 @@
 	} else if (isocdesc->start_type == START_ASAP) {
 		isocdesc->start_frame = cur_frame + START_FRAME_FUDGE;
 	}
-	/* else for start_type == START_ABSOLUTE, use start_frame as is. */
 
 	/* and see if start_frame needs any correction */
-	if (isocdesc->start_frame >= UHCI_NUMFRAMES)
-		isocdesc->start_frame -= UHCI_NUMFRAMES;
+	/* only wrap to USB frame numbers, the frame_list insertion routine
+	   takes care of the wrapping to the frame_list size */
+	isocdesc->start_frame = USB_WRAP_FRAMENR(isocdesc->start_frame);
 
 	/* and fix the end_frame value */
-	isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1;
-	if (isocdesc->end_frame >= UHCI_NUMFRAMES)
-		isocdesc->end_frame -= UHCI_NUMFRAMES;
+	isocdesc->end_frame = USB_WRAP_FRAMENR(isocdesc->start_frame + isocdesc->frame_count - 1);
 
 	isocdesc->prev_completed_frame = -1;
 	isocdesc->cur_completed_frame  = -1;
@@ -857,6 +946,7 @@
 			td->status |= TD_CTRL_IOC;
 			td->completed = isocdesc->callback_fn;
 			cb_frames = 0;
+			uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context);
 		}
 
 		bufptr += fd->frame_length;  /* or isocdesc->frame_size; */
@@ -864,21 +954,20 @@
 		/*
 		 * Insert the TD in the frame list.
 		 */
-		td->backptr = &uhci->fl->frame [cur_frame];
-		td->link    = uhci->fl->frame [cur_frame];
-		uhci->fl->frame [cur_frame] = virt_to_bus (td);
+		uhci_add_frame_list(uhci, td, cur_frame);
 
-		if (++cur_frame >= UHCI_NUMFRAMES)
-			cur_frame = 0;
+		cur_frame = USB_WRAP_FRAMENR(cur_frame+1);
 	} /* end for ix */
 
 	/*
 	 * Add IOC on the last TD.
 	 */
 	td--;
-	td->status |= TD_CTRL_IOC;
-	uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
-
+	if (!(td->status & TD_CTRL_IOC)) {
+		td->status |= TD_CTRL_IOC;
+		td->completed = isocdesc->callback_fn;
+		uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
+	}
 	return 0;
 } /* end uhci_run_isoc */
 
@@ -897,9 +986,9 @@
 	struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev);
 	struct uhci     *uhci = dev->uhci;
 	struct uhci_td  *td;
-	int             ix, cur_frame;
+	int             ix;
 
-	if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= UHCI_NUMFRAMES)) {
+	if (USB_WRAP_FRAMENR(isocdesc->start_frame) != isocdesc->start_frame) {
 #ifdef CONFIG_USB_DEBUG_ISOC
 		printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n",
 			isocdesc->start_frame);
@@ -907,13 +996,9 @@
 		return -EINVAL;
 	}
 
-	for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame;
-	     ix < isocdesc->frame_count; ix++, td++) {
+	for (ix = 0, td = isocdesc->td; ix < isocdesc->frame_count; ix++, td++) {
+		uhci_remove_frame_list(uhci, td);
 		td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC);
-		uhci->fl->frame [cur_frame] = td->link;
-
-		if (++cur_frame >= UHCI_NUMFRAMES)
-			cur_frame = 0;
 	} /* end for ix */
 
 	isocdesc->start_frame = -1;
@@ -922,18 +1007,21 @@
 
 static void uhci_free_isoc (struct usb_isoc_desc *isocdesc)
 {
+	int i;
+
 	/* If still Active, kill it. */
 	if (isocdesc->start_frame >= 0)
-		uhci_kill_isoc (isocdesc);
+		uhci_kill_isoc(isocdesc);
 
-	/* Remove it from the IRQ list. */
-	uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1]));
+	/* Remove all td's from the IRQ list. */
+	for(i = 0; i < isocdesc->frame_count; i++)
+		uhci_remove_irq_list(((struct uhci_td *)(isocdesc->td))+i);
 
 	/* Free the associate memory. */
 	if (isocdesc->td)
-		kfree (isocdesc->td);
+		kfree(isocdesc->td);
 
-	kfree (isocdesc);
+	kfree(isocdesc);
 } /* end uhci_free_isoc */
 
 /*
@@ -1512,7 +1600,7 @@
 			td, isocdesc, first_comp, cur_comp, num_comp);
 #endif
 
-	for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp];
+	for (ix = 0, fx = first_comp, prtd = ((struct uhci_td *)(isocdesc->td))+first_comp, frm = &isocdesc->frames [first_comp];
 	    ix < num_comp; ix++) {
 		frm->frame_length = uhci_actual_length (prtd->status);
 		isocdesc->total_length += frm->frame_length;
@@ -1666,6 +1754,7 @@
 
 	/* Don't clobber the frame */
 	td->link = uhci->fl->frame[0];
+	td->backptr = &uhci->fl->frame[0];
 	td->status = TD_CTRL_IOC;
 	td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN;	/* (ignored) input packet, 16 bytes, device 127 */
 	td->buffer = 0;
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/usb-core.c linux/drivers/usb/usb-core.c
--- v2.3.16/linux/drivers/usb/usb-core.c	Tue Jul 27 16:05:50 1999
+++ linux/drivers/usb/usb-core.c	Wed Sep  1 15:31:47 1999
@@ -44,6 +44,9 @@
 #	ifdef CONFIG_USB_MOUSE
 		usb_mouse_init();
 #	endif
+#       ifdef CONFIG_USB_HP_SCANNER
+                usb_hp_scanner_init();
+#       endif
 #	ifdef CONFIG_USB_KBD
 		usb_kbd_init();
 #	endif
@@ -86,6 +89,9 @@
 #	ifdef CONFIG_USB_MOUSE
         	usb_mouse_cleanup();
 #	endif
+#       ifdef CONFIG_USB_HP_SCANNER
+                usb_hp_scanner_cleanup();
+#       endif
 #endif
 }
 
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.3.16/linux/drivers/usb/usb.h	Tue Aug 31 17:29:14 1999
+++ linux/drivers/usb/usb.h	Tue Sep  7 10:19:45 1999
@@ -121,7 +121,7 @@
         void *data;
 };
 
-#define USB_PROC_CONTROL        _IOWR('U', 0, struct usb_proc_ctrltransfer)
+#define USB_PROC_CONTROL           _IOWR('U', 0, struct usb_proc_ctrltransfer)
 
 struct usb_proc_bulktransfer {
         unsigned int ep;
@@ -129,16 +129,18 @@
         void *data;
 };
 
-#define USB_PROC_BULK           _IOWR('U', 2, struct usb_proc_bulktransfer)
+#define USB_PROC_BULK              _IOWR('U', 2, struct usb_proc_bulktransfer)
 
-#define USB_PROC_RESETEP        _IOR('U', 3, unsigned int)
+#define USB_PROC_RESETEP           _IOR('U', 3, unsigned int)
 
 struct usb_proc_setinterface {
         unsigned int interface;
         unsigned int altsetting;
 };
 
-#define USB_PROC_SETINTERFACE   _IOR('U', 4, struct usb_proc_setinterface)
+#define USB_PROC_SETINTERFACE      _IOR('U', 4, struct usb_proc_setinterface)
+
+#define USB_PROC_SETCONFIGURATION  _IOR('U', 5, unsigned int)
 
 
 
@@ -349,6 +351,8 @@
  */
 #define START_FRAME_FUDGE      3
 
+#define USB_WRAP_FRAMENR(x) ((x) & 2047)
+
 /* for start_type: */
 enum {
 	START_ASAP = 0,
@@ -527,13 +531,6 @@
 extern void usb_disconnect(struct usb_device **);
 
 extern void usb_destroy_configuration(struct usb_device *dev);
-
-extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len,
-					int maxsze, usb_device_irq completed, void *dev_id);
-extern void usb_delete_isochronous (struct usb_device *dev, void *_isodesc);
-extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc);
-extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc);
-extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc);
 
 int usb_get_current_frame_number (struct usb_device *usb_dev);
 
diff -u --recursive --new-file v2.3.16/linux/drivers/usb/usb_scsi.c linux/drivers/usb/usb_scsi.c
--- v2.3.16/linux/drivers/usb/usb_scsi.c	Thu Aug 26 13:05:39 1999
+++ linux/drivers/usb/usb_scsi.c	Wed Sep  1 16:26:26 1999
@@ -92,6 +92,7 @@
 	int			ip_wanted;		/* needed */
 	int			pid;			/* control thread */
 	struct semaphore      	*notify; 		/* wait for thread to begin */
+	void			*irq_handle;		/* for USB interrupt requests */
 };
 
 /*
@@ -374,6 +375,7 @@
     __u8 status[2];
     devrequest dr;
     int retry = 5;
+    void *irq_handle;
 
     US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
     switch (us->protocol) {
@@ -409,13 +411,15 @@
 
 	/* add interrupt transfer, marked for removal */
 	us->ip_wanted = 1;
-	result = us->pusb_dev->bus->op->request_irq(us->pusb_dev, 
+	irq_handle = us->pusb_dev->bus->op->request_irq(us->pusb_dev, 
 						    usb_rcvctrlpipe(us->pusb_dev, us->ep_int),
 						     pop_CBI_irq, 0, (void *)us);
-	if (result) {
-	    US_DEBUGP("No interrupt for CBI %x\n", result);
+	if (!irq_handle) {
+	    US_DEBUGP("No interrupt for CBI\n");
 	    return DID_ABORT << 16;
 	}
+	us->irq_handle = irq_handle;
+
 	sleep_on(&us->ip_waitq);
 	if (us->ip_wanted) {
 	    US_DEBUGP("Did not get interrupt on CBI\n");
@@ -647,13 +651,17 @@
     struct us_data *us = (struct us_data *)psh->hostdata[0];
     struct us_data *prev = (struct us_data *)&us_list;
 
+    if (us->irq_handle) {
+    	usb_release_irq(us->pusb_dev, us->irq_handle);
+	us->irq_handle = NULL;
+    }
     if (us->filter)
 	us->filter->release(us->fdata);
     if (us->pusb_dev)
 	usb_deregister(&scsi_driver);
 
     /* FIXME - leaves hanging host template copy */
-    /* (bacause scsi layer uses it after removal !!!) */
+    /* (because scsi layer uses it after removal !!!) */
     while(prev->next != us)
 	prev = prev->next;
     prev->next = us->next;
@@ -1280,6 +1288,7 @@
 	    dev->descriptor.idProduct == 0x0001) {
 	    devrequest dr;
 	    __u8 qstat[2];
+	    void *irq_handle;
 
 	    /* shuttle E-USB */
 	    dr.requesttype = 0xC0;
@@ -1290,9 +1299,12 @@
 	    ss->pusb_dev->bus->op->control_msg(ss->pusb_dev, usb_rcvctrlpipe(dev,0), &dr, qstat, 2);
 	    US_DEBUGP("C0 status %x %x\n", qstat[0], qstat[1]);
 	    init_waitqueue_head(&ss->ip_waitq);
-	    ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, 
+	    irq_handle = ss->pusb_dev->bus->op->request_irq(ss->pusb_dev, 
 						usb_rcvctrlpipe(ss->pusb_dev, ss->ep_int),
 						pop_CBI_irq, 0, (void *)ss);
+	    if (!irq_handle)
+	    	return -1;
+	    ss->irq_handle = irq_handle;
 	    interruptible_sleep_on_timeout(&ss->ip_waitq, HZ*5);
 
 	} else if (ss->protocol == US_PR_CBI)
diff -u --recursive --new-file v2.3.16/linux/fs/Config.in linux/fs/Config.in
--- v2.3.16/linux/fs/Config.in	Thu Aug 12 12:26:06 1999
+++ linux/fs/Config.in	Sat Sep  4 12:42:30 1999
@@ -31,6 +31,11 @@
   define_bool CONFIG_JOLIET n
 fi
 
+tristate 'UDF filesystem support' CONFIG_UDF_FS
+if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool '   UDF read-write support (EXPERIMENTAL)' CONFIG_UDF_RW
+fi
+
 tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS
 if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -71,11 +76,10 @@
   if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
   fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'NFS server support' CONFIG_NFSD
-    if [ "$CONFIG_NFSD" != "n" ]; then
-      bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
-    fi
+  # considering that RedHat-6.0 ships with this on, I guess it's not really experimental
+  tristate 'NFS server support' CONFIG_NFSD
+  if [ "$CONFIG_NFSD" != "n" ]; then
+    bool '   Emulate SUN NFS server' CONFIG_NFSD_SUN
   fi
   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
     define_bool CONFIG_SUNRPC y
diff -u --recursive --new-file v2.3.16/linux/fs/Makefile linux/fs/Makefile
--- v2.3.16/linux/fs/Makefile	Thu Aug 12 12:26:06 1999
+++ linux/fs/Makefile	Sat Sep  4 12:42:30 1999
@@ -18,7 +18,7 @@
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
 		hpfs sysv smbfs ncpfs ufs efs affs romfs autofs hfs lockd \
-		nfsd nls devpts adfs partitions qnx4
+		nfsd nls devpts adfs partitions qnx4 udf
 
 SUB_DIRS := partitions
 
@@ -222,6 +222,14 @@
 else
   ifeq ($(CONFIG_QNX4FS_FS),m)
   MOD_SUB_DIRS += qnx4
+  endif
+endif
+
+ifeq ($(CONFIG_UDF_FS),y)
+SUB_DIRS += udf
+else
+  ifeq ($(CONFIG_UDF_FS),m)
+  MOD_SUB_DIRS += udf
   endif
 endif
 
diff -u --recursive --new-file v2.3.16/linux/fs/buffer.c linux/fs/buffer.c
--- v2.3.16/linux/fs/buffer.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/buffer.c	Fri Sep  3 10:29:38 1999
@@ -898,19 +898,21 @@
  */
 void __bforget(struct buffer_head * buf)
 {
+	/* grab the lru lock here to block bdflush. */
 	spin_lock(&lru_list_lock);
 	write_lock(&hash_table_lock);
-	if (atomic_read(&buf->b_count) != 1 || buffer_locked(buf)) {
-		touch_buffer(buf);
-		atomic_dec(&buf->b_count);
-	} else {
-		atomic_set(&buf->b_count, 0);
-		buf->b_state = 0;
-		if (buf->b_pprev)
-			__hash_unlink(buf);
-		__remove_from_lru_list(buf, buf->b_list);
-		put_last_free(buf);
-	}
+	if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
+		goto in_use;
+	if (buf->b_pprev)
+		__hash_unlink(buf);
+	write_unlock(&hash_table_lock);
+	__remove_from_lru_list(buf, buf->b_list);
+	spin_unlock(&lru_list_lock);
+	buf->b_state = 0;
+	put_last_free(buf);
+	return;
+
+ in_use:
 	write_unlock(&hash_table_lock);
 	spin_unlock(&lru_list_lock);
 }
@@ -1231,16 +1233,12 @@
 		 */
 		if (offset <= curr_off) {
 			if (buffer_mapped(bh)) {
-				atomic_inc(&bh->b_count);
-				wait_on_buffer(bh);
-				if (bh->b_dev == B_FREE)
-					BUG();
 				mark_buffer_clean(bh);
+				wait_on_buffer(bh);
 				clear_bit(BH_Uptodate, &bh->b_state);
 				clear_bit(BH_Mapped, &bh->b_state);
 				clear_bit(BH_Req, &bh->b_state);
 				bh->b_blocknr = 0;
-				atomic_dec(&bh->b_count);
 			}
 		}
 		curr_off = next_off;
@@ -1258,8 +1256,7 @@
 	 * instead.
 	 */
 	if (!offset) {
-		if (!try_to_free_buffers(page))
-		{
+		if (!try_to_free_buffers(page)) {
 			atomic_add(PAGE_CACHE_SIZE, &buffermem);
 			return 0;
 		}
diff -u --recursive --new-file v2.3.16/linux/fs/exec.c linux/fs/exec.c
--- v2.3.16/linux/fs/exec.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/exec.c	Tue Sep  7 10:57:20 1999
@@ -274,7 +274,7 @@
 		mpnt->vm_ops = NULL;
 		mpnt->vm_offset = 0;
 		mpnt->vm_file = NULL;
-		mpnt->vm_pte = 0;
+		mpnt->vm_private_data = NULL;
 		insert_vm_struct(current->mm, mpnt);
 		current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
 	} 
diff -u --recursive --new-file v2.3.16/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.3.16/linux/fs/ext2/inode.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/ext2/inode.c	Fri Sep  3 10:24:35 1999
@@ -856,10 +856,11 @@
 	unsigned int	flags;
 	
 	retval = -EPERM;
-	if ((iattr->ia_attr_flags &
-	     (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
-	    (inode->u.ext2_i.i_flags &
-	     (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL))) {
+	if (iattr->ia_valid & ATTR_ATTR_FLAG &&
+	    ((!(iattr->ia_attr_flags & ATTR_FLAG_APPEND) !=
+	      !(inode->u.ext2_i.i_flags & EXT2_APPEND_FL)) ||
+	     (!(iattr->ia_attr_flags & ATTR_FLAG_IMMUTABLE) !=
+	      !(inode->u.ext2_i.i_flags & EXT2_IMMUTABLE_FL)))) {
 		if (!capable(CAP_LINUX_IMMUTABLE))
 			goto out;
 	} else if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
diff -u --recursive --new-file v2.3.16/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.3.16/linux/fs/filesystems.c	Thu May 13 23:50:15 1999
+++ linux/fs/filesystems.c	Sat Sep  4 12:42:30 1999
@@ -26,6 +26,7 @@
 #include <linux/romfs_fs.h>
 #include <linux/auto_fs.h>
 #include <linux/qnx4_fs.h>
+#include <linux/udf_fs.h>
 #include <linux/ntfs_fs.h>
 #include <linux/hfs_fs.h>
 #include <linux/devpts_fs.h>
@@ -148,6 +149,10 @@
 
 #ifdef CONFIG_QNX4FS_FS
 	init_qnx4_fs();
+#endif
+
+#ifdef CONFIG_UDF_FS
+	init_udf_fs();
 #endif
    
 #ifdef CONFIG_NLS
diff -u --recursive --new-file v2.3.16/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.3.16/linux/fs/ncpfs/sock.c	Tue Aug 31 17:29:14 1999
+++ linux/fs/ncpfs/sock.c	Fri Sep  3 12:45:30 1999
@@ -176,7 +176,7 @@
 		   instructions adding the wait_table waitqueues in the
 		   waitqueue-head before going to calculate the mask-retval. */
 		__set_current_state(TASK_INTERRUPTIBLE);
-		if (!(file->f_op->poll(file, &wait_table) & POLLIN)) {
+		if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
 			int timed_out;
 			if (timeout > max_timeout) {
 				/* JEJB/JSP 2/7/94
diff -u --recursive --new-file v2.3.16/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.3.16/linux/fs/nfsd/vfs.c	Mon Jul  5 20:34:31 1999
+++ linux/fs/nfsd/vfs.c	Thu Sep  2 10:18:33 1999
@@ -995,12 +995,15 @@
  * that the parent is still our parent and
  * that we are still hashed onto it..
  *
- * This is requied in case two processes race
+ * This is required in case two processes race
  * on removing (or moving) the same entry: the
  * parent lock will serialize them, but the
  * other process will be too late..
+ *
+ * Note that this nfsd_check_parent is different
+ * than the one in linux/include/dcache_func.h.
  */
-#define check_parent(dir, dentry) \
+#define nfsd_check_parent(dir, dentry) \
 	((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
 
 /*
@@ -1079,8 +1082,8 @@
 	nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
 	err = -ENOENT;
 	/* GAM3 check for parent changes after locking. */
-	if (check_parent(fdir, odentry) &&
-	    check_parent(tdir, ndentry)) {
+	if (nfsd_check_parent(fdir, odentry) &&
+	    nfsd_check_parent(tdir, ndentry)) {
 
 		err = vfs_rename(fdir, odentry, tdir, ndentry);
 		if (!err && EX_ISSYNC(tfhp->fh_export)) {
@@ -1168,7 +1171,7 @@
 		fhp->fh_locked = 1;
 
 		err = -ENOENT;
-		if (check_parent(dirp, rdentry))
+		if (nfsd_check_parent(dirp, rdentry))
 			err = vfs_rmdir(dirp, rdentry);
 
 		rdentry->d_count--;
diff -u --recursive --new-file v2.3.16/linux/fs/partitions/Config.in linux/fs/partitions/Config.in
--- v2.3.16/linux/fs/partitions/Config.in	Tue Aug 31 17:29:14 1999
+++ linux/fs/partitions/Config.in	Sat Sep  4 13:09:36 1999
@@ -13,7 +13,10 @@
   if [ "$ARCH" = "ppc" -o "$CONFIG_MAC" = "y" ]; then
     define_bool CONFIG_MAC_PARTITION y
   fi
-  define_bool CONFIG_MSDOS_PARTITION y
+  if [ "$CONFIG_AMIGA" != "y" -a "$CONFIG_ATARI" != "y" -a \
+       "$CONFIG_MAC" != "y" ]; then
+    define_bool CONFIG_MSDOS_PARTITION y
+  fi
 fi
 if [ "$CONFIG_MSDOS_PARTITION" = "y" ]; then
   bool '  BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
diff -u --recursive --new-file v2.3.16/linux/fs/partitions/atari.c linux/fs/partitions/atari.c
--- v2.3.16/linux/fs/partitions/atari.c	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/atari.c	Sat Sep  4 13:09:36 1999
@@ -13,7 +13,9 @@
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/blk.h>
+#include <linux/ctype.h>
 
+#include <asm/byteorder.h>
 #include <asm/system.h>
 
 #include "check.h"
@@ -23,6 +25,14 @@
  */
 #define ICD_PARTS
 
+/* check if a partition entry looks valid -- Atari format is assumed if at
+   least one of the primary entries is ok this way */
+#define	VALID_PARTITION(pi,hdsiz)					     \
+    (((pi)->flg & 1) &&							     \
+     isalnum((pi)->id[0]) && isalnum((pi)->id[1]) && isalnum((pi)->id[2]) && \
+     be32_to_cpu((pi)->st) <= (hdsiz) &&				     \
+     be32_to_cpu((pi)->st) + be32_to_cpu((pi)->siz) <= (hdsiz))
+
 int atari_partition (struct gendisk *hd, kdev_t dev,
 		     unsigned long first_sector, int first_part_minor)
 {
@@ -30,9 +40,8 @@
   struct buffer_head *bh;
   struct rootsector *rs;
   struct partition_info *pi;
-  ulong extensect;
-  unsigned int psum;
-  int i;
+  u32 extensect;
+  u32 hd_size;
 #ifdef ICD_PARTS
   int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
 #endif
@@ -44,16 +53,18 @@
   }
 
   /* Verify this is an Atari rootsector: */
-  psum = 0;
-  for (i=0;i<256;i++) {
-    psum+=ntohs(((__u16 *) (bh->b_data))[i]);
-  }
-  if ((psum & 0xFFFF) != 0x1234) {
-    brelse(bh);
-    return 0;
+  rs = (struct rootsector *) bh->b_data;
+  hd_size = hd->part[minor - 1].nr_sects;
+  if (!VALID_PARTITION(&rs->part[0], hd_size) &&
+      !VALID_PARTITION(&rs->part[1], hd_size) &&
+      !VALID_PARTITION(&rs->part[2], hd_size) &&
+      !VALID_PARTITION(&rs->part[3], hd_size)) {
+      /* if there's no valid primary partition, assume that no Atari
+	 format partition table (there's no reliable magic or the like
+	 :-() */
+      return 0;
   }
 
-  rs = (struct rootsector *) bh->b_data;
   pi = &rs->part[0];
   printk (" AHDI");
   for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++)
@@ -72,7 +83,7 @@
 	      part_fmt = 1;
 #endif
 	      printk(" XGM<");
-	      partsect = extensect = ntohl(pi->st);
+	      partsect = extensect = be32_to_cpu(pi->st);
 	      while (1)
 		{
 		  xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev));
@@ -93,8 +104,9 @@
 		    break;
 		  }
 
-		  add_gd_partition(hd, minor, partsect + ntohl(xrs->part[0].st),
-				ntohl(xrs->part[0].siz));
+		  add_gd_partition(hd, minor,
+				   partsect + be32_to_cpu(xrs->part[0].st),
+				   be32_to_cpu(xrs->part[0].siz));
 
 		  if (!(xrs->part[1].flg & 1)) {
 		    /* end of linked partition list */
@@ -107,7 +119,7 @@
 		    break;
 		  }
 
-		  partsect = ntohl(xrs->part[1].st) + extensect;
+		  partsect = be32_to_cpu(xrs->part[1].st) + extensect;
 		  brelse (xbh);
 		  minor++;
 		  if (minor >= m_lim) {
@@ -120,7 +132,8 @@
 	  else
 	    {
 	      /* we don't care about other id's */
-	      add_gd_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz));
+	      add_gd_partition (hd, minor, be32_to_cpu(pi->st),
+				be32_to_cpu(pi->siz));
 	    }
 	}
     }
@@ -147,7 +160,8 @@
              memcmp (pi->id, "RAW", 3) == 0) )
         {
           part_fmt = 2;
-	  add_gd_partition (hd, minor, ntohl(pi->st), ntohl(pi->siz));
+	  add_gd_partition (hd, minor, be32_to_cpu(pi->st),
+			    be32_to_cpu(pi->siz));
         }
       }
       printk(" >");
diff -u --recursive --new-file v2.3.16/linux/fs/partitions/atari.h linux/fs/partitions/atari.h
--- v2.3.16/linux/fs/partitions/atari.h	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/atari.h	Sat Sep  4 13:09:36 1999
@@ -13,10 +13,10 @@
 
 struct partition_info
 {
-  u_char flg;			/* bit 0: active; bit 7: bootable */
+  u8 flg;			/* bit 0: active; bit 7: bootable */
   char id[3];			/* "GEM", "BGM", "XGM", or other */
-  u_long st;			/* start of partition */
-  u_long siz;			/* length of partition */
+  u32 st;			/* start of partition */
+  u32 siz;			/* length of partition */
 };
 
 struct rootsector
@@ -24,11 +24,11 @@
   char unused[0x156];		/* room for boot code */
   struct partition_info icdpart[8];	/* info for ICD-partitions 5..12 */
   char unused2[0xc];
-  u_long hd_siz;		/* size of disk in blocks */
+  u32 hd_siz;			/* size of disk in blocks */
   struct partition_info part[4];
-  u_long bsl_st;		/* start of bad sector list */
-  u_long bsl_cnt;		/* length of bad sector list */
-  u_short checksum;		/* checksum for bootable disks */
+  u32 bsl_st;			/* start of bad sector list */
+  u32 bsl_cnt;			/* length of bad sector list */
+  u16 checksum;			/* checksum for bootable disks */
 } __attribute__((__packed__));
 
 int atari_partition (struct gendisk *hd, kdev_t dev,
diff -u --recursive --new-file v2.3.16/linux/fs/partitions/mac.c linux/fs/partitions/mac.c
--- v2.3.16/linux/fs/partitions/mac.c	Thu Aug 12 12:26:06 1999
+++ linux/fs/partitions/mac.c	Sat Sep  4 13:09:36 1999
@@ -1,5 +1,5 @@
 /*
- *  fs/partitions/msdos.c
+ *  fs/partitions/mac.c
  *
  *  Code extracted from drivers/block/genhd.c
  *  Copyright (C) 1991-1998  Linus Torvalds
diff -u --recursive --new-file v2.3.16/linux/fs/pipe.c linux/fs/pipe.c
--- v2.3.16/linux/fs/pipe.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/pipe.c	Mon Sep  6 09:48:36 1999
@@ -213,7 +213,7 @@
 			wake_up_interruptible(PIPE_WAIT(*inode));
 			pipe_wait(inode);
 			if (signal_pending(current))
-				goto out;
+				goto out_nolock;
 			if (down_interruptible(PIPE_SEM(*inode)))
 				goto out_nolock;
 			if (!PIPE_READERS(*inode))
diff -u --recursive --new-file v2.3.16/linux/fs/read_write.c linux/fs/read_write.c
--- v2.3.16/linux/fs/read_write.c	Thu Aug 26 13:05:40 1999
+++ linux/fs/read_write.c	Tue Sep  7 10:22:12 1999
@@ -13,7 +13,7 @@
 
 #include <asm/uaccess.h>
 
-static loff_t default_llseek(struct file *file, loff_t offset, int origin)
+loff_t default_llseek(struct file *file, loff_t offset, int origin)
 {
 	long long retval;
 
diff -u --recursive --new-file v2.3.16/linux/fs/udf/Makefile linux/fs/udf/Makefile
--- v2.3.16/linux/fs/udf/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/Makefile	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,16 @@
+#
+# Makefile for the linux udf-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .o file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile..
+
+O_TARGET := udf.o
+O_OBJS   := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
+		partition.o super.o truncate.o symlink.o fsync.o \
+		crc.o directory.o misc.o udftime.o unicode.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.3.16/linux/fs/udf/balloc.c linux/fs/udf/balloc.c
--- v2.3.16/linux/fs/udf/balloc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/balloc.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,441 @@
+/*
+ * balloc.c
+ *
+ * PURPOSE
+ *	Block allocation handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ *  02/24/99 blf  Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/udf_fs.h>
+
+#include <asm/bitops.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+static int read_block_bitmap(struct super_block * sb, unsigned int block,
+	unsigned long bitmap_nr)
+{
+	struct buffer_head *bh = NULL;
+	int retval = 0;
+	lb_addr loc;
+
+	loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap;
+	loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
+
+	bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block), sb->s_blocksize);
+	if (!bh)
+	{
+		retval = -EIO;
+	}
+	UDF_SB_BLOCK_BITMAP_NUMBER(sb, bitmap_nr) = block;
+	UDF_SB_BLOCK_BITMAP(sb, bitmap_nr) = bh;
+	return retval;
+}
+
+static int load__block_bitmap(struct super_block * sb, unsigned int block_group)
+{
+	int i, j, retval = 0;
+	unsigned long block_bitmap_number;
+	struct buffer_head * block_bitmap = NULL;
+	int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) +
+		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+
+	if (block_group >= nr_groups)
+	{
+		udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
+	}
+
+	if (nr_groups <= UDF_MAX_BLOCK_LOADED)
+	{
+		if (UDF_SB_BLOCK_BITMAP(sb, block_group))
+		{
+			if (UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group)
+				return block_group;
+		}
+		retval = read_block_bitmap(sb, block_group, block_group);
+		if (retval < 0)
+			return retval;
+		return block_group;
+	}
+
+	for (i=0; i<UDF_SB_LOADED_BLOCK_BITMAPS(sb) &&
+		UDF_SB_BLOCK_BITMAP_NUMBER(sb, i) != block_group; i++)
+	{
+		;
+	}
+	if (i < UDF_SB_LOADED_BLOCK_BITMAPS(sb) &&
+		UDF_SB_BLOCK_BITMAP_NUMBER(sb, i) == block_group)
+	{
+		block_bitmap_number = UDF_SB_BLOCK_BITMAP_NUMBER(sb, i);
+		block_bitmap = UDF_SB_BLOCK_BITMAP(sb, i);
+		for (j=i; j>0; j--)
+		{
+			UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
+			UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
+		}
+		UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) = block_bitmap_number;
+		UDF_SB_BLOCK_BITMAP(sb, 0) = block_bitmap;
+
+		if (!block_bitmap)
+			retval = read_block_bitmap(sb, block_group, 0);
+	}
+	else
+	{
+		if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) < UDF_MAX_BLOCK_LOADED)
+			UDF_SB_LOADED_BLOCK_BITMAPS(sb) ++;
+		else
+			brelse(UDF_SB_BLOCK_BITMAP(sb, UDF_MAX_BLOCK_LOADED-1));
+		for (j=UDF_SB_LOADED_BLOCK_BITMAPS(sb)-1; j>0; j--)
+		{
+			UDF_SB_BLOCK_BITMAP_NUMBER(sb, j) = UDF_SB_BLOCK_BITMAP_NUMBER(sb, j-1);
+			UDF_SB_BLOCK_BITMAP(sb, j) = UDF_SB_BLOCK_BITMAP(sb, j-1);
+		}
+		retval = read_block_bitmap(sb, block_group, 0);
+	}
+	return retval;
+}
+
+static inline int load_block_bitmap(struct super_block *sb,
+	unsigned int block_group)
+{
+	int slot;
+    int nr_groups = (UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)) +
+        (sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+
+	if (UDF_SB_LOADED_BLOCK_BITMAPS(sb) > 0 &&
+		UDF_SB_BLOCK_BITMAP_NUMBER(sb, 0) == block_group &&
+		UDF_SB_BLOCK_BITMAP(sb, block_group))
+	{
+		return 0;
+	}
+	else if (nr_groups <= UDF_MAX_BLOCK_LOADED &&
+		UDF_SB_BLOCK_BITMAP_NUMBER(sb, block_group) == block_group &&
+		UDF_SB_BLOCK_BITMAP(sb, block_group))
+	{
+		slot = block_group;
+	}
+	else
+	{
+		slot = load__block_bitmap(sb, block_group);
+	}
+
+	if (slot < 0)
+		return slot;
+
+	if (!UDF_SB_BLOCK_BITMAP(sb, slot))
+		return -EIO;
+
+	return slot;
+}
+
+void udf_free_blocks(const struct inode * inode, lb_addr bloc, Uint32 offset,
+	Uint32 count)
+{
+	struct buffer_head * bh = NULL;
+	unsigned long block;
+	unsigned long block_group;
+	unsigned long bit;
+	unsigned long i;
+	int bitmap_nr;
+	unsigned long overflow;
+	struct super_block * sb;
+
+	sb = inode->i_sb;
+	if (!sb)
+	{
+		udf_debug("nonexistent device");
+		return;
+	}
+
+	if (UDF_SB_PARTMAPS(sb)[bloc.partitionReferenceNum].s_uspace_bitmap == 0xFFFFFFFF)
+		return;
+
+	lock_super(sb);
+	if (bloc.logicalBlockNum < 0 ||
+		(bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
+	{
+		udf_debug("%d < %d || %d + %d > %d\n",
+			bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+			UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+		goto error_return;
+	}
+
+	block = bloc.logicalBlockNum + offset + (sizeof(struct SpaceBitmapDesc) << 3);
+
+do_more:
+	overflow = 0;
+	block_group = block >> (sb->s_blocksize_bits + 3);
+	bit = block % (sb->s_blocksize << 3);
+
+	/*
+	 * Check to see if we are freeing blocks across a group boundary.
+	 */
+	if (bit + count > (sb->s_blocksize << 3))
+	{
+		overflow = bit + count - (sb->s_blocksize << 3);
+		count -= overflow;
+	}
+	bitmap_nr = load_block_bitmap(sb, block_group);
+	if (bitmap_nr < 0)
+		goto error_return;
+
+	bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+	for (i=0; i < count; i++)
+	{
+		if (udf_set_bit(bit + i, bh->b_data))
+		{
+			udf_debug("bit %ld already set\n", bit + i);
+			udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
+		}
+		else if (UDF_SB_LVIDBH(sb))
+		{
+			UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1);
+		}
+	}
+	mark_buffer_dirty(bh, 1);
+	if (overflow)
+	{
+		block += count;
+		count = overflow;
+		goto do_more;
+	}
+error_return:
+	sb->s_dirt = 1;
+	if (UDF_SB_LVIDBH(sb))
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	unlock_super(sb);
+	return;
+}
+
+int udf_alloc_blocks(const struct inode * inode, Uint16 partition,
+	Uint32 first_block, Uint32 block_count)
+{
+	int alloc_count = 0;
+	int bit, block, block_group, group_start;
+	int nr_groups, bitmap_nr;
+	struct buffer_head *bh;
+	struct super_block *sb;
+
+	sb = inode->i_sb;
+	if (!sb)
+	{
+		udf_debug("nonexistent device\n");
+		return 0;
+	}
+	lock_super(sb);
+
+	if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
+		goto out;
+
+repeat:
+	nr_groups = (UDF_SB_PARTLEN(sb, partition) +
+		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+	block = first_block + (sizeof(struct SpaceBitmapDesc) << 3);
+	block_group = block >> (sb->s_blocksize_bits + 3);
+	group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
+
+	bitmap_nr = load_block_bitmap(sb, block_group);
+	if (bitmap_nr < 0)
+		goto out;
+	bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+
+	bit = block % (sb->s_blocksize << 3);
+
+	while (bit < (sb->s_blocksize << 3) && block_count > 0)
+	{
+		if (!udf_test_bit(bit, bh->b_data))
+			goto out;
+		if (!udf_clear_bit(bit, bh->b_data))
+		{
+			udf_debug("bit already cleared for block %d\n", bit);
+			goto out;
+		}
+		block_count --;
+		alloc_count ++;
+		bit ++;
+		block ++;
+
+	}
+	mark_buffer_dirty(bh, 1);
+	if (block_count > 0)
+		goto repeat;
+out:
+	if (UDF_SB_LVIDBH(sb))
+	{
+		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	}
+	sb->s_dirt = 1;
+	unlock_super(sb);
+	return alloc_count;
+}
+
+int udf_new_block(const struct inode * inode, Uint16 partition, Uint32 goal, int *err)
+{
+	int tmp, newbit, bit=0, block, block_group, group_start;
+	int end_goal, nr_groups, bitmap_nr, i;
+	struct buffer_head *bh = NULL;
+	struct super_block *sb;
+	char *ptr;
+	int newblock = 0;
+
+	*err = -ENOSPC;
+	sb = inode->i_sb;
+	if (!sb)
+	{
+		udf_debug("nonexistent device\n");
+		return newblock;
+	}
+	lock_super(sb);
+
+repeat:
+	if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
+		goal = 0;
+
+	nr_groups = (UDF_SB_PARTLEN(sb, partition) +
+		(sizeof(struct SpaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+	block = goal + (sizeof(struct SpaceBitmapDesc) << 3);
+	block_group = block >> (sb->s_blocksize_bits + 3);
+	group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
+
+	bitmap_nr = load_block_bitmap(sb, block_group);
+	if (bitmap_nr < 0)
+		goto error_return;
+	bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+	ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+
+	if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
+	{
+		bit = block % (sb->s_blocksize << 3);
+
+		if (udf_test_bit(bit, bh->b_data))
+		{
+			goto got_block;
+		}
+		end_goal = (bit + 63) & ~63;
+		bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
+		if (bit < end_goal)
+			goto got_block;
+		ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
+		newbit = (ptr - ((char *)bh->b_data)) << 3;
+		if (newbit < sb->s_blocksize << 3)
+		{
+			bit = newbit;
+			goto search_back;
+		}
+		newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
+		if (newbit < sb->s_blocksize << 3)
+		{
+			bit = newbit;
+			goto got_block;
+		}
+	}
+
+	for (i=0; i<(nr_groups*2); i++)
+	{
+		block_group ++;
+		if (block_group >= nr_groups)
+			block_group = 0;
+		group_start = block_group ? 0 : sizeof(struct SpaceBitmapDesc);
+
+		bitmap_nr = load_block_bitmap(sb, block_group);
+		if (bitmap_nr < 0)
+			goto error_return;
+		bh = UDF_SB_BLOCK_BITMAP(sb, bitmap_nr);
+		if (i < nr_groups)
+		{
+			ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+			if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
+			{
+				bit = (ptr - ((char *)bh->b_data)) << 3;
+				break;
+			}
+		}
+		else
+		{
+			bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3);
+			if (bit < sb->s_blocksize << 3)
+				break;
+		}
+	}
+	if (i >= (nr_groups*2))
+	{
+		unlock_super(sb);
+		return newblock;
+	}
+	if (bit < sb->s_blocksize << 3)
+		goto search_back;
+	else
+		bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
+	if (bit >= sb->s_blocksize << 3)
+	{
+		unlock_super(sb);
+		return 0;
+	}
+
+search_back:
+	for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--);
+
+got_block:
+	newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
+		(group_start << 3);
+
+	tmp = udf_get_pblock(sb, newblock, partition, 0);
+	if (!udf_clear_bit(bit, bh->b_data))
+	{
+		udf_debug("bit already cleared for block %d\n", bit);
+		goto repeat;
+	}
+
+	mark_buffer_dirty(bh, 1);
+	if (!(bh = getblk(sb->s_dev, tmp, sb->s_blocksize)))
+	{
+		udf_debug("cannot get block %d\n", tmp);
+		unlock_super(sb);
+		return 0;
+	}
+	memset(bh->b_data, 0, sb->s_blocksize);
+	mark_buffer_uptodate(bh, 1);
+	mark_buffer_dirty(bh, 1);
+	udf_release_data(bh);
+
+	if (UDF_SB_LVIDBH(sb))
+	{
+		UDF_SB_LVID(sb)->freeSpaceTable[partition] =
+			cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	}
+	sb->s_dirt = 1;
+	unlock_super(sb);
+	*err = 0;
+	return newblock;
+
+error_return:
+	*err = -EIO;
+	unlock_super(sb);
+	return 0;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/crc.c linux/fs/udf/crc.c
--- v2.3.16/linux/fs/udf/crc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/crc.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,178 @@
+/*
+ * crc.c
+ *
+ * PURPOSE
+ *	Routines to generate, calculate, and test a 16-bit CRC.
+ *
+ * DESCRIPTION
+ *	The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories
+ *	and Ned W. Rhodes of Software Systems Group. It has been published in
+ *	"Design and Validation of Computer Protocols", Prentice Hall,
+ *	Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4.
+ *
+ *	Copyright is held by AT&T.
+ *
+ *	AT&T gives permission for the free use of the CRC source code.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ */
+
+#include "udfdecl.h"
+
+static Uint16 crc_table[256] = {
+	0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
+	0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
+	0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
+	0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
+	0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
+	0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
+	0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
+	0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
+	0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
+	0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
+	0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
+	0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
+	0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
+	0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
+	0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
+	0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
+	0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
+	0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
+	0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
+	0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
+	0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
+	0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
+	0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
+	0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
+	0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
+	0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
+	0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
+	0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
+	0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
+	0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
+	0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
+	0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
+};
+
+/*
+ * udf_crc
+ *
+ * PURPOSE
+ *	Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
+ *
+ * DESCRIPTION
+ *	The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
+ *	The polynomial used is:	x^16 + x^12 + x^15 + 1
+ *
+ * PRE-CONDITIONS
+ *	data		Pointer to the data block.
+ *	size		Size of the data block.
+ *
+ * POST-CONDITIONS
+ *	<return>	CRC of the data block.
+ *
+ * HISTORY
+ *	July 21, 1997 - Andrew E. Mileski
+ *	Adapted from OSTA-UDF(tm) 1.50 standard.
+ */
+extern Uint16
+udf_crc(Uint8 *data, Uint32 size, Uint16 crc)
+{
+	while (size--)
+		crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
+
+	return crc;
+}
+
+/****************************************************************************/
+#if defined(TEST)
+
+/*
+ * PURPOSE
+ *	Test udf_crc()
+ *
+ * HISTORY
+ *	July 21, 1997 - Andrew E. Mileski
+ *	Adapted from OSTA-UDF(tm) 1.50 standard.
+ */
+
+unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U };
+
+int main(void)
+{
+	unsigned short x;
+
+	x = udf_crc16(bytes, sizeof bytes);
+	printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
+
+	return 0;
+}
+
+#endif /* defined(TEST) */
+
+/****************************************************************************/
+#if defined(GENERATE)
+
+/*
+ * PURPOSE
+ *	Generate a table for fast 16-bit CRC calculations (any polynomial).
+ *
+ * DESCRIPTION
+ *	The ITU-T V.41 polynomial is 010041.
+ *
+ * HISTORY
+ *	July 21, 1997 - Andrew E. Mileski
+ *	Adapted from OSTA-UDF(tm) 1.50 standard.
+ */
+
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+	unsigned long crc, poly;
+	int n, i;
+
+	/* Get the polynomial */
+	sscanf(argv[1], "%lo", &poly);
+	if (poly & 0xffff0000U){
+		fprintf(stderr, "polynomial is too large\en");
+		exit(1);
+	}
+
+	printf("/* CRC 0%o */\n", poly);
+
+	/* Create a table */
+	printf("static unsigned short crc_table[256] = {\n");
+	for (n = 0; n < 256; n++){
+		if (n % 8 == 0)
+			printf("\t");
+		crc = n << 8;
+		for (i = 0; i < 8; i++){
+			if(crc & 0x8000U)
+				crc = (crc << 1) ^ poly;
+			else
+				crc <<= 1;
+		crc &= 0xFFFFU;
+		}
+		if (n == 255)
+			printf("0x%04xU ", crc);
+		else
+			printf("0x%04xU, ", crc);
+		if(n % 8 == 7)
+			printf("\n");
+	}
+	printf("};\n");
+
+	return 0;
+}
+
+#endif /* defined(GENERATE) */
diff -u --recursive --new-file v2.3.16/linux/fs/udf/dir.c linux/fs/udf/dir.c
--- v2.3.16/linux/fs/udf/dir.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/dir.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,296 @@
+/*
+ * dir.c
+ *
+ * PURPOSE
+ *  Directory handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ *  10/05/98 dgb  Split directory operations into it's own file
+ *                Implemented directory reads via do_udf_readdir
+ *  10/06/98      Made directory operations work!
+ *  11/17/98      Rewrote directory to support ICB_FLAG_AD_LONG
+ *  11/25/98 blf  Rewrote directory handling (readdir+lookup) to support reading
+ *                across blocks.
+ *  12/12/98      Split out the lookup code to namei.c. bulk of directory
+ *                code now in directory.c:udf_fileident_read.
+ */
+
+#include "udfdecl.h"
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/version.h>
+#include "udf_i.h"
+#include "udf_sb.h"
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/udf_fs.h>
+#endif
+
+/* Prototypes for file operations */
+static int udf_readdir(struct file *, void *, filldir_t);
+static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
+
+/* readdir and lookup functions */
+
+static struct file_operations udf_dir_operations = {
+	NULL,			/* lllseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	udf_readdir,	/* readdir */
+	NULL,			/* poll */
+	udf_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	NULL,			/* open */
+	NULL,			/* flush */
+	NULL,			/* release */
+	udf_sync_file,	/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL,			/* revalidate */
+	NULL			/* lock */
+};
+
+struct inode_operations udf_dir_inode_operations = {
+	&udf_dir_operations,
+#ifdef CONFIG_UDF_RW
+	udf_create, 	/* create */
+#else
+	NULL,			/* create */
+#endif
+	udf_lookup,		/* lookup */
+#ifdef CONFIG_UDF_RW
+	udf_link,		/* link */
+	udf_unlink,		/* unlink */
+	udf_symlink,	/* symlink */
+	udf_mkdir,		/* mkdir */
+	udf_rmdir,		/* rmdir */
+	udf_mknod,		/* mknod */
+	udf_rename,		/* rename */
+#else
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+#endif
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* get_block */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* flushpage */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
+};
+
+/*
+ * udf_readdir
+ *
+ * PURPOSE
+ *	Read a directory entry.
+ *
+ * DESCRIPTION
+ *	Optional - sys_getdents() will return -ENOTDIR if this routine is not
+ *	available.
+ *
+ *	Refer to sys_getdents() in fs/readdir.c
+ *	sys_getdents() -> .
+ *
+ * PRE-CONDITIONS
+ *	filp			Pointer to directory file.
+ *	buf			Pointer to directory entry buffer.
+ *	filldir			Pointer to filldir function.
+ *
+ * POST-CONDITIONS
+ *	<return>		>=0 on success.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+
+int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode *dir = filp->f_dentry->d_inode;
+	int result;
+
+	if (!dir)
+	   return -EBADF;
+
+ 	if (!S_ISDIR(dir->i_mode))
+	   return -ENOTDIR;
+
+	if ( filp->f_pos == 0 ) 
+	{
+		if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino) < 0)
+			return 0;
+	}
+ 
+	result = do_udf_readdir(dir, filp, filldir, dirent);
+	UPDATE_ATIME(dir);
+ 	return result;
+}
+
+static int 
+do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
+{
+	struct udf_fileident_bh fibh;
+	struct FileIdentDesc *fi=NULL;
+	struct FileIdentDesc cfi;
+	int block, iblock;
+	int nf_pos = filp->f_pos;
+	int flen;
+	char fname[255];
+	char *nameptr;
+	Uint16 liu;
+	Uint8 lfi;
+	int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+	struct buffer_head * bh = NULL;
+	lb_addr bloc, eloc;
+	Uint32 extoffset, elen, offset;
+
+	if (nf_pos >= size)
+		return 1;
+
+	if (nf_pos == 0)
+		nf_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+	fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
+		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+	{
+		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+		if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+		{
+			if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+				extoffset -= sizeof(short_ad);
+			else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+				extoffset -= sizeof(long_ad);
+		}
+		else
+			offset = 0;
+	}
+	else
+	{
+		udf_release_data(bh);
+		return 0;
+	}
+
+	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+	{
+		udf_release_data(bh);
+		return 0;
+	}
+
+	while ( nf_pos < size )
+	{
+		filp->f_pos = nf_pos;
+
+		fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh);
+		liu = le16_to_cpu(cfi.lengthOfImpUse);
+		lfi = cfi.lengthFileIdent;
+
+		if (!fi)
+		{
+			if (fibh.sbh != fibh.ebh)
+				udf_release_data(fibh.ebh);
+			udf_release_data(fibh.sbh);
+			udf_release_data(bh);
+			return 1;
+		}
+
+		if (fibh.sbh == fibh.ebh)
+			nameptr = fi->fileIdent + liu;
+		else
+		{
+			int poffset;	/* Unpaded ending offset */
+
+			poffset = fibh.soffset + sizeof(struct FileIdentDesc) + liu + lfi;
+
+			if (poffset >= lfi)
+				nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
+			else
+			{
+				nameptr = fname;
+				memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+				memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
+			}
+		}
+
+		if ( (cfi.fileCharacteristics & FILE_DELETED) != 0 )
+		{
+			if ( !IS_UNDELETE(dir->i_sb) )
+				continue;
+		}
+		
+		if ( (cfi.fileCharacteristics & FILE_HIDDEN) != 0 )
+		{
+			if ( !IS_UNHIDE(dir->i_sb) )
+				continue;
+		}
+
+		iblock = udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0);
+ 
+ 		if (!lfi) /* parent directory */
+ 		{
+			if (filldir(dirent, "..", 2, filp->f_pos, filp->f_dentry->d_parent->d_inode->i_ino) < 0)
+			{
+				if (fibh.sbh != fibh.ebh)
+					udf_release_data(fibh.ebh);
+				udf_release_data(fibh.sbh);
+				udf_release_data(bh);
+ 				return 1;
+			}
+		}
+		else
+		{
+			if ((flen = udf_get_filename(nameptr, fname, lfi)))
+			{
+				if (filldir(dirent, fname, flen, filp->f_pos, iblock) < 0)
+				{
+					if (fibh.sbh != fibh.ebh)
+						udf_release_data(fibh.ebh);
+					udf_release_data(fibh.sbh);
+					udf_release_data(bh);
+		 			return 1; /* halt enum */
+				}
+			}
+			else
+			{
+				udf_debug("size=%d, nf_pos=%d, liu=%d, lfi=%d\n", size, nf_pos, liu, lfi);
+			}
+		}
+	} /* end while */
+
+	filp->f_pos = nf_pos;
+
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	udf_release_data(bh);
+
+	if ( filp->f_pos >= size)
+		return 1;
+	else
+		return 0;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/directory.c linux/fs/udf/directory.c
--- v2.3.16/linux/fs/udf/directory.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/directory.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,332 @@
+/*
+ * directory.c
+ *
+ * PURPOSE
+ *	Directory related functions
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ */
+
+#include "udfdecl.h"
+#include "udf_sb.h"
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/udf_fs.h>
+
+#else
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#endif
+
+#ifdef __KERNEL__
+
+Uint8 * udf_filead_read(struct inode *dir, Uint8 *tmpad, Uint8 ad_size,
+	lb_addr fe_loc, int *pos, int *offset, struct buffer_head **bh, int *error)
+{
+	int loffset = *offset;
+	int block;
+	Uint8 *ad;
+	int remainder;
+
+	*error = 0;
+
+	ad = (Uint8 *)(*bh)->b_data + *offset;
+	*offset += ad_size;
+
+	if (!ad)
+	{
+		udf_release_data(*bh);
+		*error = 1;
+		return NULL;
+	}
+
+	if (*offset == dir->i_sb->s_blocksize)
+	{
+		udf_release_data(*bh);
+		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
+		if (!block)
+			return NULL;
+		if (!(*bh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+			return NULL;
+	}
+	else if (*offset > dir->i_sb->s_blocksize)
+	{
+		ad = tmpad;
+
+		remainder = dir->i_sb->s_blocksize - loffset;
+		memcpy((Uint8 *)ad, (*bh)->b_data + loffset, remainder);
+
+		udf_release_data(*bh);
+		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
+		if (!block)
+			return NULL;
+		if (!((*bh) = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+			return NULL;
+
+		memcpy((Uint8 *)ad + remainder, (*bh)->b_data, ad_size - remainder);
+		*offset = ad_size - remainder;
+	}
+	return ad;
+}
+
+struct FileIdentDesc *
+udf_fileident_read(struct inode *dir, int *nf_pos,
+	struct udf_fileident_bh *fibh,
+	struct FileIdentDesc *cfi,
+	lb_addr *bloc, Uint32 *extoffset, 
+	Uint32 *offset, struct buffer_head **bh)
+{
+	struct FileIdentDesc *fi;
+	lb_addr eloc;
+	Uint32 elen;
+	int block;
+
+	fibh->soffset = fibh->eoffset;
+
+	if (fibh->eoffset == dir->i_sb->s_blocksize)
+	{
+		int lextoffset = *extoffset;
+
+		if (udf_next_aext(dir, bloc, extoffset, &eloc, &elen, bh, 1) !=
+			EXTENT_RECORDED_ALLOCATED)
+		{
+			return NULL;
+		}
+
+		block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
+
+		(*offset) ++;
+
+		if (*offset >= (elen >> dir->i_sb->s_blocksize_bits))
+			*offset = 0;
+		else
+			*extoffset = lextoffset;
+
+		udf_release_data(fibh->sbh);
+		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+			return NULL;
+		fibh->soffset = fibh->eoffset = 0;
+	}
+	else if (fibh->sbh != fibh->ebh)
+	{
+		udf_release_data(fibh->sbh);
+		fibh->sbh = fibh->ebh;
+	}
+
+	fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
+		&(fibh->eoffset));
+
+	if (!fi)
+		return NULL;
+
+	*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
+
+	if (fibh->eoffset <= dir->i_sb->s_blocksize)
+	{
+		memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc));
+	}
+	else if (fibh->eoffset > dir->i_sb->s_blocksize)
+	{
+		int lextoffset = *extoffset;
+
+		if (udf_next_aext(dir, bloc, extoffset, &eloc, &elen, bh, 1) !=
+			EXTENT_RECORDED_ALLOCATED)
+		{
+			return NULL;
+		}
+
+		block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
+
+		(*offset) ++;
+
+		if (*offset >= (elen >> dir->i_sb->s_blocksize_bits))
+			*offset = 0;
+		else
+			*extoffset = lextoffset;
+
+		fibh->soffset -= dir->i_sb->s_blocksize;
+		fibh->eoffset -= dir->i_sb->s_blocksize;
+
+		if (!(fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+			return NULL;
+
+		if (sizeof(struct FileIdentDesc) > - fibh->soffset)
+		{
+			int fi_len;
+
+			memcpy((Uint8 *)cfi, (Uint8 *)fi, - fibh->soffset);
+			memcpy((Uint8 *)cfi - fibh->soffset, fibh->ebh->b_data,
+				sizeof(struct FileIdentDesc) + fibh->soffset);
+
+			fi_len = (sizeof(struct FileIdentDesc) + cfi->lengthFileIdent +
+				le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+
+			*nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
+			fibh->eoffset = fibh->soffset + fi_len;
+		}
+		else
+		{
+			memcpy((Uint8 *)cfi, (Uint8 *)fi, sizeof(struct FileIdentDesc));
+		}
+	}
+	return fi;
+}
+#endif
+
+struct FileIdentDesc * 
+udf_get_fileident(void * buffer, int bufsize, int * offset)
+{
+	struct FileIdentDesc *fi;
+	int lengthThisIdent;
+	Uint8 * ptr;
+	int padlen;
+
+	if ( (!buffer) || (!offset) ) {
+#ifdef __KERNEL__
+		udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
+#endif
+		return NULL;
+	}
+
+	ptr = buffer;
+
+	if ( (*offset > 0) && (*offset < bufsize) ) {
+		ptr += *offset;
+	}
+	fi=(struct FileIdentDesc *)ptr;
+	if (le16_to_cpu(fi->descTag.tagIdent) != TID_FILE_IDENT_DESC)
+	{
+#ifdef __KERNEL__
+		udf_debug("0x%x != TID_FILE_IDENT_DESC\n",
+			le16_to_cpu(fi->descTag.tagIdent));
+		udf_debug("offset: %u sizeof: %u bufsize: %u\n",
+			*offset, sizeof(struct FileIdentDesc), bufsize);
+#endif
+		return NULL;
+	}
+	if ( (*offset + sizeof(struct FileIdentDesc)) > bufsize )
+	{
+		lengthThisIdent = sizeof(struct FileIdentDesc);
+	}
+	else
+		lengthThisIdent = sizeof(struct FileIdentDesc) +
+			fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+
+	/* we need to figure padding, too! */
+	padlen = lengthThisIdent % UDF_NAME_PAD;
+	if (padlen)
+		lengthThisIdent += (UDF_NAME_PAD - padlen);
+	*offset = *offset + lengthThisIdent;
+
+	return fi;
+}
+
+extent_ad *
+udf_get_fileextent(void * buffer, int bufsize, int * offset)
+{
+	extent_ad * ext;
+	struct FileEntry *fe;
+	Uint8 * ptr;
+
+	if ( (!buffer) || (!offset) )
+	{
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
+#endif
+		return NULL;
+	}
+
+	fe = (struct FileEntry *)buffer;
+
+	if ( le16_to_cpu(fe->descTag.tagIdent) != TID_FILE_ENTRY )
+	{
+#ifdef __KERNEL__
+		udf_debug("0x%x != TID_FILE_ENTRY\n",
+			le16_to_cpu(fe->descTag.tagIdent));
+#endif
+		return NULL;
+	}
+
+	ptr=(Uint8 *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
+
+	if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
+	{
+		ptr += *offset;
+	}
+
+	ext = (extent_ad *)ptr;
+
+	*offset = *offset + sizeof(extent_ad);
+	return ext;
+}
+
+short_ad *
+udf_get_fileshortad(void * buffer, int maxoffset, int *offset, int inc)
+{
+	short_ad * sa;
+	Uint8 * ptr;
+
+	if ( (!buffer) || (!offset) )
+	{
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
+#endif
+		return NULL;
+	}
+
+	ptr = (Uint8 *)buffer;
+
+	if ( (*offset > 0) && (*offset < maxoffset) )
+		ptr += *offset;
+	else
+		return NULL;
+
+	if ((sa = (short_ad *)ptr)->extLength == 0)
+		return NULL;
+	else if (inc)
+		(*offset) += sizeof(short_ad);
+	return sa;
+}
+
+long_ad *
+udf_get_filelongad(void * buffer, int maxoffset, int * offset, int inc)
+{
+	long_ad * la;
+	Uint8 * ptr;
+
+	if ( (!buffer) || !(offset) ) 
+	{
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
+#endif
+		return NULL;
+	}
+
+	ptr = (Uint8 *)buffer;
+
+	if ( (*offset > 0) && (*offset < maxoffset) )
+		ptr += *offset;
+	else
+		return NULL;
+
+	if ((la = (long_ad *)ptr)->extLength == 0)
+		return NULL;
+	else if (inc)
+		(*offset) += sizeof(long_ad);
+	return la;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/file.c linux/fs/udf/file.c
--- v2.3.16/linux/fs/udf/file.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/file.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,443 @@
+/*
+ * file.c
+ *
+ * PURPOSE
+ *  File handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *  E-mail regarding any portion of the Linux UDF file system should be
+ *  directed to the development team mailing list (run by majordomo):
+ *    linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *  This file is distributed under the terms of the GNU General Public
+ *  License (GPL). Copies of the GPL can be obtained from:
+ *    ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *  Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998-1999 Dave Boynton
+ *  (C) 1998-1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ *  10/02/98 dgb  Attempt to integrate into udf.o
+ *  10/07/98      Switched to using generic_readpage, etc., like isofs
+ *                And it works!
+ *  12/06/98 blf  Added udf_file_read. uses generic_file_read for all cases but
+ *                ICB_FLAG_AD_IN_ICB.
+ *  04/06/99      64 bit file handling on 32 bit systems taken from ext2 file.c
+ *  05/12/99      Preliminary file write support
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/udf_fs.h>
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/string.h> /* memset */
+#include <linux/errno.h>
+#include <linux/locks.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+#define NBUF	32
+
+typedef void * poll_table; 
+
+static long long udf_file_llseek(struct file *, long long, int);
+static ssize_t udf_file_read_adinicb (struct file *, char *, size_t, loff_t *);
+static ssize_t udf_file_write (struct file *, const char *, size_t, loff_t *);
+#if BITS_PER_LONG < 64
+static int udf_open_file(struct inode *, struct file *);
+#endif
+static int udf_release_file(struct inode *, struct file *);
+
+static struct file_operations udf_file_operations = {
+	udf_file_llseek,	/* llseek */
+	generic_file_read,	/* read */
+	udf_file_write,		/* write */
+	NULL,				/* readdir */
+	NULL,				/* poll */
+	udf_ioctl,			/* ioctl */
+	generic_file_mmap,	/* mmap */
+#if BITS_PER_LONG == 64
+	NULL, 				/* open */
+#else
+	udf_open_file,		/* open */
+#endif
+	NULL,				/* flush */
+	udf_release_file,	/* release */
+	udf_sync_file,		/* fsync */
+	NULL,				/* fasync */
+	NULL,				/* check_media_change */
+	NULL,				/* revalidate */
+	NULL				/* lock */
+};
+
+struct inode_operations udf_file_inode_operations = {
+	&udf_file_operations,
+	NULL,					/* create */
+	NULL,					/* lookup */
+	NULL,					/* link */
+	NULL,					/* unlink */
+	NULL,					/* symlink */
+	NULL,					/* mkdir */
+	NULL,					/* rmdir */
+	NULL,					/* mknod */
+	NULL,					/* rename */
+	NULL,					/* readlink */
+	NULL,					/* follow_link */
+	udf_get_block,			/* get_block */
+	block_read_full_page,	/* readpage */
+	block_write_full_page,	/* writepage */
+	block_flushpage,		/* flushpage */
+#ifdef CONFIG_UDF_RW
+	udf_truncate,			/* truncate */
+#else
+	NULL,					/* truncate */
+#endif
+	NULL,					/* permission */
+	NULL,					/* smap */
+	NULL					/* revalidate */
+};
+
+static struct file_operations udf_file_operations_adinicb = {
+	udf_file_llseek,	/* llseek */
+	udf_file_read_adinicb,/* read */
+	udf_file_write,		/* write */
+	NULL,				/* readdir */
+	NULL,				/* poll */
+	udf_ioctl,			/* ioctl */
+	NULL,				/* mmap */
+	NULL, 				/* open */
+	NULL,				/* flush */
+	udf_release_file,	/* release */
+	udf_sync_file,		/* fsync */
+	NULL,				/* fasync */
+	NULL,				/* check_media_change */
+	NULL,				/* revalidate */
+	NULL				/* lock */
+};
+
+struct inode_operations udf_file_inode_operations_adinicb = {
+	&udf_file_operations_adinicb,
+	NULL,					/* create */
+	NULL,					/* lookup */
+	NULL,					/* link */
+	NULL,					/* unlink */
+	NULL,					/* symlink */
+	NULL,					/* mkdir */
+	NULL,					/* rmdir */
+	NULL,					/* mknod */
+	NULL,					/* rename */
+	NULL,					/* readlink */
+	NULL,					/* follow_link */
+	udf_get_block,			/* get_block */
+	block_read_full_page,	/* readpage */
+	block_write_full_page,	/* writepage */
+	block_flushpage,		/* flushpage */
+#ifdef CONFIG_UDF_RW
+	udf_truncate,			/* truncate */
+#else
+	NULL,					/* truncate */
+#endif
+	NULL,					/* permission */
+	NULL,					/* smap */
+	NULL					/* revalidate */
+};
+
+/*
+ * Make sure the offset never goes beyond the 32-bit mark..
+ */
+static long long udf_file_llseek(struct file * file, long long offset, int origin)
+{
+	struct inode * inode = file->f_dentry->d_inode;
+
+	switch (origin)
+	{
+		case 2:
+		{
+			offset += inode->i_size;
+			break;
+		}
+		case 1:
+		{
+			offset += file->f_pos;
+			break;
+		}
+	}
+	if (((unsigned long long) offset >> 32) != 0)
+	{
+#if BITS_PER_LONG < 64
+		return -EINVAL;
+#else
+		if (offset > ???)
+			return -EINVAL;
+#endif
+	}
+	if (offset != file->f_pos)
+	{
+		file->f_pos = offset;
+		file->f_reada = 0;
+		file->f_version = ++event;
+	}
+	return offset;
+}
+
+static inline void remove_suid(struct inode * inode)
+{
+	unsigned int mode;
+
+	/* set S_IGID if S_IXGRP is set, and always set S_ISUID */
+	mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID;
+
+	/* was any of the uid bits set? */
+	mode &= inode->i_mode;
+	if (mode && !capable(CAP_FSETID))
+	{
+		inode->i_mode &= ~mode;
+		mark_inode_dirty(inode);
+	}
+}
+
+static ssize_t udf_file_write(struct file * file, const char * buf,
+	size_t count, loff_t *ppos)
+{
+	ssize_t retval;
+	struct inode *inode = file->f_dentry->d_inode;
+	remove_suid(inode);
+
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		int i, err;
+		struct buffer_head *bh;
+
+		if ((bh = udf_expand_adinicb(inode, &i, 0, &err)))
+			udf_release_data(bh);
+	}
+
+	retval = generic_file_write(file, buf, count, ppos, block_write_partial_page);
+
+	if (retval > 0)
+	{
+		inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+		UDF_I_UCTIME(inode) = UDF_I_UMTIME(inode) = CURRENT_UTIME;
+	}
+	mark_inode_dirty(inode);
+	return retval;
+}
+
+/*
+ * udf_file_read
+ *
+ * PURPOSE
+ *	Read from an open file.
+ *
+ * DESCRIPTION
+ *	Optional - sys_read() will return -EINVAL if this routine is not
+ *	available.
+ *
+ *	Refer to sys_read() in fs/read_write.c
+ *	sys_read() -> .
+ *
+ *	Note that you can use generic_file_read() instead, which requires that
+ *	udf_readpage() be available, but you can use generic_readpage(), which
+ *	requires that udf_block_map() be available. Reading will then be done by
+ *	memory-mapping the file a page at a time. This is not suitable for
+ *	devices that don't handle read-ahead [example: CD-R/RW that may have
+ *	blank sectors that shouldn't be read].
+ *
+ *	Refer to generic_file_read() in mm/filemap.c and to generic_readpage()
+ *	in fs/buffer.c
+ *
+ *	Block devices can use block_read() instead. Refer to fs/block_dev.c
+ *
+ * PRE-CONDITIONS
+ *	inode			Pointer to inode to read from (never NULL).
+ *	filp			Pointer to file to read from (never NULL).
+ *	buf			Point to read buffer (validated).
+ *	bufsize			Size of read buffer.
+ *
+ * POST-CONDITIONS
+ *	<return>		Bytes read (>=0) or an error code (<0) that
+ *				sys_read() will return.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static ssize_t udf_file_read_adinicb(struct file * filp, char * buf,
+	size_t bufsize, loff_t * loff)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	Uint32 size, left, pos, block;
+	struct buffer_head *bh = NULL;
+
+	size = inode->i_size;
+	if (*loff > size)
+		left = 0;
+	else
+		left = size - *loff;
+	if (left > bufsize)
+		left = bufsize;
+
+	if (left <= 0)
+		return 0;
+
+	pos = *loff + UDF_I_EXT0OFFS(inode);
+	block = udf_block_map(inode, 0);
+	if (!(bh = udf_tread(inode->i_sb,
+		udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+		inode->i_sb->s_blocksize)))
+	{
+		return 0;
+	}
+	if (!copy_to_user(buf, bh->b_data + pos, left))
+		*loff += left;
+	else
+		return -EFAULT;
+
+	return left;
+}
+
+/*
+ * udf_ioctl
+ *
+ * PURPOSE
+ *	Issue an ioctl.
+ *
+ * DESCRIPTION
+ *	Optional - sys_ioctl() will return -ENOTTY if this routine is not
+ *	available, and the ioctl cannot be handled without filesystem help.
+ *
+ *	sys_ioctl() handles these ioctls that apply only to regular files:
+ *		FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
+ *	These ioctls are also handled by sys_ioctl():
+ *		FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
+ *	All other ioctls are passed to the filesystem.
+ *
+ *	Refer to sys_ioctl() in fs/ioctl.c
+ *	sys_ioctl() -> .
+ *
+ * PRE-CONDITIONS
+ *	inode			Pointer to inode that ioctl was issued on.
+ *	filp			Pointer to file that ioctl was issued on.
+ *	cmd			The ioctl command.
+ *	arg			The ioctl argument [can be interpreted as a
+ *				user-space pointer if desired].
+ *
+ * POST-CONDITIONS
+ *	<return>		Success (>=0) or an error code (<=0) that
+ *				sys_ioctl() will return.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+	unsigned long arg)
+{
+	int result=-1;
+	int size;
+	struct buffer_head *bh = NULL;
+	struct FileEntry *fe;
+	Uint16 ident;
+
+	if ( permission(inode, MAY_READ) != 0 )
+	{
+		udf_debug("no permission to access inode %lu\n",
+						inode->i_ino);
+		return -EPERM;
+	}
+
+	if ( !arg )
+	{
+		udf_debug("invalid argument to udf_ioctl\n");
+		return -EINVAL;
+	}
+
+	/* first, do ioctls that don't need to udf_read */
+	switch (cmd)
+	{
+		case UDF_GETVOLIDENT:
+			if ( (result == verify_area(VERIFY_WRITE, (char *)arg, 32)) == 0)
+				result = copy_to_user((char *)arg, UDF_SB_VOLIDENT(inode->i_sb), 32);
+			return result;
+
+	}
+
+	/* ok, we need to read the inode */
+	bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
+
+	if (!bh || ident != TID_FILE_ENTRY)
+	{
+		udf_debug("bread failed (ino=%ld) or ident (%d) != TID_FILE_ENTRY",
+			inode->i_ino, ident);
+		return -EFAULT;
+	}
+
+	fe = (struct FileEntry *)bh->b_data;
+	size = le32_to_cpu(fe->lengthExtendedAttr);
+
+	switch (cmd) 
+	{
+		case UDF_GETEASIZE:
+			if ( (result = verify_area(VERIFY_WRITE, (char *)arg, 4)) == 0) 
+				result= put_user(size, (int *)arg);
+			break;
+
+		case UDF_GETEABLOCK:
+			if ( (result = verify_area(VERIFY_WRITE, (char *)arg, size)) == 0) 
+				result= copy_to_user((char *)arg, fe->extendedAttr, size);
+			break;
+
+		default:
+			udf_debug("ino=%ld, cmd=%d\n", inode->i_ino, cmd);
+			break;
+	}
+
+	udf_release_data(bh);
+	return result;
+}
+
+/*
+ * udf_release_file
+ *
+ * PURPOSE
+ *  Called when all references to the file are closed
+ *
+ * DESCRIPTION
+ *  Discard prealloced blocks
+ *
+ * HISTORY
+ *
+ */
+static int udf_release_file(struct inode * inode, struct file * filp)
+{
+	if (filp->f_mode & FMODE_WRITE)
+		udf_discard_prealloc(inode);
+	return 0;
+}
+
+#if BITS_PER_LONG < 64
+/*
+ * udf_open_file
+ *
+ * PURPOSE
+ *  Called when an inode is about to be open.
+ *
+ * DESCRIPTION
+ *  Use this to disallow opening RW large files on 32 bit systems.
+ *
+ * HISTORY
+ *
+ */
+static int udf_open_file(struct inode * inode, struct file * filp)
+{
+	if (inode->i_size == (Uint32)-1 && (filp->f_mode & FMODE_WRITE))
+		return -EFBIG;
+	return 0;
+}
+#endif
diff -u --recursive --new-file v2.3.16/linux/fs/udf/fsync.c linux/fs/udf/fsync.c
--- v2.3.16/linux/fs/udf/fsync.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/fsync.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,110 @@
+/*
+ * fsync.c
+ *
+ * PURPOSE
+ *  Fsync handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *  E-mail regarding any portion of the Linux UDF file system should be
+ *  directed to the development team mailing list (run by majordomo):
+ *      linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *  This file is distributed under the terms of the GNU General Public
+ *  License (GPL). Copies of the GPL can be obtained from:
+ *      ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *  Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ *  05/22/99 blf  Created.
+ *
+ */
+
+#include "udfdecl.h"
+
+#include <linux/fs.h>
+#include <linux/udf_fs.h>
+#include "udf_i.h"
+
+static int sync_extent_block (struct inode * inode, Uint32 block, int wait)
+{
+	struct buffer_head * bh;
+	
+	if (!block)
+		return 0;
+	bh = get_hash_table (inode->i_dev, block, inode->i_sb->s_blocksize);
+	if (!bh)
+		return 0;
+	if (wait && buffer_req(bh) && !buffer_uptodate(bh)) {
+		brelse (bh);
+		return -1;
+	}
+	if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) {
+		brelse (bh);
+		return 0;
+	}
+	ll_rw_block (WRITE, 1, &bh);
+	atomic_dec(&bh->b_count);
+	return 0;
+}
+
+static int sync_all_extents(struct inode * inode, int wait)
+{
+	lb_addr bloc, eloc;
+	Uint32 extoffset, lextoffset, elen, offset, block;
+	int err = 0, etype;
+	struct buffer_head *bh = NULL;
+	
+	if ((etype = inode_bmap(inode, 0, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1)
+	{
+		block = udf_get_lb_pblock(inode->i_sb, bloc, 0);
+		err |= sync_extent_block(inode, block, wait);
+		lextoffset = extoffset;
+
+		while ((etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+		{
+			if (lextoffset > extoffset)
+			{
+				block = udf_get_lb_pblock(inode->i_sb, bloc, 0);
+				err |= sync_extent_block(inode, block, wait);
+			}
+			lextoffset = extoffset;
+		}
+	}
+	udf_release_data(bh);
+	return err;
+}
+
+/*
+ *	File may be NULL when we are called. Perhaps we shouldn't
+ *	even pass file to fsync ?
+ */
+
+int udf_sync_file(struct file * file, struct dentry *dentry)
+{
+	int wait, err = 0;
+	struct inode *inode = dentry->d_inode;
+
+	if ((S_ISLNK(inode->i_mode) && !(inode->i_blocks)) ||
+		UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		/*
+		 * Don't sync fast links! or ICB_FLAG_AD_IN_ICB
+		 */
+		goto skip;
+	}
+
+	err = generic_buffer_fdatasync(inode, 0, ~0UL);
+
+	for (wait=0; wait<=1; wait++)
+	{
+		err |= sync_all_extents (inode, wait);
+	}
+skip:
+	err |= udf_sync_inode (inode);
+	return err ? -EIO : 0;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/ialloc.c linux/fs/udf/ialloc.c
--- v2.3.16/linux/fs/udf/ialloc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/ialloc.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,169 @@
+/*
+ * ialloc.c
+ *
+ * PURPOSE
+ *	Inode allocation handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ *  02/24/99 blf  Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/locks.h>
+#include <linux/udf_fs.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+void udf_free_inode(struct inode * inode)
+{
+	struct super_block * sb = inode->i_sb;
+	int is_directory;
+	unsigned long ino;
+
+	if (!inode->i_dev)
+	{
+		udf_debug("inode has no device\n");
+		return;
+	}
+	if (inode->i_count > 1)
+	{
+		udf_debug("inode has count=%d\n", inode->i_count);
+		return;
+	}
+	if (inode->i_nlink)
+	{
+		udf_debug("inode has nlink=%d\n", inode->i_nlink);
+		return;
+	}
+	if (!sb)
+	{
+		udf_debug("inode on nonexistent device\n");
+		return;
+	}
+
+	ino = inode->i_ino;
+
+	lock_super(sb);
+
+	is_directory = S_ISDIR(inode->i_mode);
+
+	clear_inode(inode);
+
+	if (UDF_SB_LVIDBH(sb))
+	{
+		if (is_directory)
+			UDF_SB_LVIDIU(sb)->numDirs =
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1);
+		else
+			UDF_SB_LVIDIU(sb)->numFiles =
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
+		
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	}
+
+	unlock_super(sb);
+
+	udf_free_blocks(inode, UDF_I_LOCATION(inode), 0, 1);
+}
+
+struct inode * udf_new_inode (const struct inode *dir, int mode, int * err)
+{
+	struct super_block *sb;
+	struct inode * inode;
+	int block;
+	Uint32 start = UDF_I_LOCATION(dir).logicalBlockNum;
+
+	inode = get_empty_inode();
+	if (!inode)
+	{
+		*err = -ENOMEM;
+		return NULL;
+	}
+	sb = dir->i_sb;
+	inode->i_sb = sb;
+	inode->i_flags = 0;
+	*err = -ENOSPC;
+
+	block = udf_new_block(dir, UDF_I_LOCATION(dir).partitionReferenceNum,
+		start, err);
+	if (*err)
+	{
+		iput(inode);
+		return NULL;
+	}
+	lock_super(sb);
+
+	if (UDF_SB_LVIDBH(sb))
+	{
+		struct LogicalVolHeaderDesc *lvhd;
+		Uint64 uniqueID;
+		lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
+		if (S_ISDIR(mode))
+			UDF_SB_LVIDIU(sb)->numDirs =
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1);
+		else
+			UDF_SB_LVIDIU(sb)->numFiles =
+				cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1);
+		UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID);
+		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
+			uniqueID += 16;
+		lvhd->uniqueID = cpu_to_le64(uniqueID);
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	}
+	inode->i_mode = mode;
+	inode->i_sb = sb;
+	inode->i_nlink = 1;
+	inode->i_dev = sb->s_dev;
+	inode->i_uid = current->fsuid;
+	if (dir->i_mode & S_ISGID)
+	{
+		inode->i_gid = dir->i_gid;
+		if (S_ISDIR(mode))
+			mode |= S_ISGID;
+	}
+	else
+		inode->i_gid = current->fsgid;
+	UDF_I_LOCATION(inode).logicalBlockNum = block;
+	UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
+	inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
+	inode->i_blksize = PAGE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_size = 0;
+	UDF_I_LENEATTR(inode) = 0;
+	UDF_I_LENALLOC(inode) = 0;
+	UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode);
+	UDF_I_EXT0LEN(inode) = 0;
+#if 1
+	UDF_I_EXT0OFFS(inode) = sizeof(struct FileEntry);
+	UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_IN_ICB;
+#else
+	UDF_I_EXT0OFFS(inode) = 0;
+	UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+#endif
+
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	UDF_I_UMTIME(inode) = UDF_I_UATIME(inode) = UDF_I_UCTIME(inode) = CURRENT_UTIME;
+	inode->i_op = NULL;
+	insert_inode_hash(inode);
+	mark_inode_dirty(inode);
+	unlock_super(sb);
+	*err = 0;
+	return inode;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/inode.c linux/fs/udf/inode.c
--- v2.3.16/linux/fs/udf/inode.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/inode.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,1944 @@
+/*
+ * inode.c
+ *
+ * PURPOSE
+ *  Inode handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *  E-mail regarding any portion of the Linux UDF file system should be
+ *  directed to the development team mailing list (run by majordomo):
+ *    linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *  This file is distributed under the terms of the GNU General Public
+ *  License (GPL). Copies of the GPL can be obtained from:
+ *    ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *  Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998 Dave Boynton
+ *  (C) 1998-1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ *  10/04/98 dgb  Added rudimentary directory functions
+ *  10/07/98      Fully working udf_block_map! It works!
+ *  11/25/98      bmap altered to better support extents
+ *  12/06/98 blf  partition support in udf_iget, udf_block_map and udf_read_inode
+ *  12/12/98      rewrote udf_block_map to handle next extents and descs across
+ *                block boundaries (which is not actually allowed)
+ *  12/20/98      added support for strategy 4096
+ *  03/07/99      rewrote udf_block_map (again)
+ *                New funcs, inode_bmap, udf_next_aext
+ *  04/19/99      Support for writing device EA's for major/minor #
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+#define EXTENT_MERGE_SIZE 5
+
+static mode_t udf_convert_permissions(struct FileEntry *);
+static int udf_update_inode(struct inode *, int);
+static void udf_fill_inode(struct inode *, struct buffer_head *);
+static struct buffer_head *inode_getblk(struct inode *, long, int *, long *, int *);
+static void udf_split_extents(struct inode *, int *, int, int,
+	long_ad [EXTENT_MERGE_SIZE], int *);
+static void udf_prealloc_extents(struct inode *, int, int,
+	 long_ad [EXTENT_MERGE_SIZE], int *);
+static void udf_merge_extents(struct inode *,
+	 long_ad [EXTENT_MERGE_SIZE], int *);
+static void udf_update_extents(struct inode *,
+	long_ad [EXTENT_MERGE_SIZE], int, int,
+	lb_addr, Uint32, struct buffer_head **);
+
+static DECLARE_MUTEX(read_semaphore);
+
+/*
+ * udf_put_inode
+ *
+ * PURPOSE
+ *
+ * DESCRIPTION
+ *	This routine is called whenever the kernel no longer needs the inode.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ *
+ *  Called at each iput()
+ */
+void udf_put_inode(struct inode * inode)
+{
+	udf_discard_prealloc(inode);
+}
+
+/*
+ * udf_delete_inode
+ *
+ * PURPOSE
+ *	Clean-up before the specified inode is destroyed.
+ *
+ * DESCRIPTION
+ *	This routine is called when the kernel destroys an inode structure
+ *	ie. when iput() finds i_count == 0.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ *
+ *  Called at the last iput() if i_nlink is zero.
+ */
+void udf_delete_inode(struct inode * inode)
+{
+	inode->i_size = 0;
+	if (inode->i_blocks)
+		udf_truncate(inode);
+	udf_free_inode(inode);
+}
+
+void udf_discard_prealloc(struct inode * inode)
+{
+#ifdef UDF_PREALLOCATE
+#if 0
+	unsigned short total;
+	lb_addr loc = UDF_I_LOCATION(inode);
+
+	if (UDF_I_PREALLOC_COUNT(inode))
+	{
+		total = UDF_I_PREALLOC_COUNT(inode);
+		UDF_I_PREALLOC_COUNT(inode) = 0;
+		loc.logicalBlockNum = UDF_I_PREALLOC_BLOCK(inode);
+		udf_free_blocks(inode, loc, 0, total);
+	}
+#endif
+#endif
+}
+
+static int udf_alloc_block(struct inode *inode, Uint16 partition,
+	Uint32 goal, int *err)
+{
+	int result = 0;
+	wait_on_super(inode->i_sb);
+
+	result = udf_new_block(inode, partition, goal, err);
+
+	return result;
+}
+
+struct buffer_head * udf_expand_adinicb(struct inode *inode, int *block, int isdir, int *err)
+{
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		long_ad newad;
+		int newblock;
+		struct buffer_head *sbh = NULL, *dbh = NULL;
+
+		if (!UDF_I_LENALLOC(inode))
+		{
+			UDF_I_EXT0OFFS(inode) = 0;
+			UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+			return NULL;
+		}
+
+		/* alloc block, and copy data to it */
+		*block = udf_alloc_block(inode,
+			UDF_I_LOCATION(inode).partitionReferenceNum,
+			UDF_I_LOCATION(inode).logicalBlockNum, err);
+
+		if (!(*block))
+			return NULL;
+		newblock = udf_get_pblock(inode->i_sb, *block,
+			UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+		if (!newblock)
+			return NULL;
+		sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+		if (!sbh)
+			return NULL;
+		dbh = udf_tread(inode->i_sb, newblock, inode->i_sb->s_blocksize);
+		if (!dbh)
+			return NULL;
+		
+		if (isdir)
+		{
+			struct udf_fileident_bh sfibh, dfibh;
+			int f_pos = UDF_I_EXT0OFFS(inode) >> 2;
+			int size = (UDF_I_EXT0OFFS(inode) + inode->i_size) >> 2;
+			struct FileIdentDesc cfi, *sfi, *dfi;
+
+			sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
+			sfibh.sbh = sfibh.ebh = sbh;
+			dfibh.soffset = dfibh.eoffset = 0;
+			dfibh.sbh = dfibh.ebh = dbh;
+			while ( (f_pos < size) )
+			{
+				sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
+				if (!sfi)
+				{
+					udf_release_data(sbh);
+					udf_release_data(dbh);
+					return NULL;
+				}
+				sfi->descTag.tagLocation = *block;
+				dfibh.soffset = dfibh.eoffset;
+				dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
+				dfi = (struct FileIdentDesc *)(dbh->b_data + dfibh.soffset);
+				if (udf_write_fi(sfi, dfi, &dfibh, sfi->impUse,
+					sfi->fileIdent + sfi->lengthOfImpUse))
+				{
+					udf_release_data(sbh);
+					udf_release_data(dbh);
+					return NULL;
+				}
+			}
+		}
+		else
+		{
+			memcpy(dbh->b_data, sbh->b_data + udf_file_entry_alloc_offset(inode),
+				UDF_I_LENALLOC(inode));
+		}
+		mark_buffer_dirty(dbh, 1);
+
+		memset(sbh->b_data + udf_file_entry_alloc_offset(inode),
+			0, UDF_I_LENALLOC(inode));
+
+		newad.extLength = UDF_I_EXT0LEN(inode) = inode->i_size;
+		newad.extLocation.logicalBlockNum = *block;
+		newad.extLocation.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+		UDF_I_EXT0LOC(inode) = newad.extLocation;
+		/* UniqueID stuff */
+
+		memcpy(sbh->b_data + udf_file_entry_alloc_offset(inode),
+			&newad, sizeof(newad));
+
+		UDF_I_LENALLOC(inode) = sizeof(newad);
+		UDF_I_EXT0OFFS(inode) = 0;
+		UDF_I_ALLOCTYPE(inode) = ICB_FLAG_AD_LONG;
+		inode->i_blocks += inode->i_sb->s_blocksize / 512;
+		udf_release_data(sbh);
+		mark_inode_dirty(inode);
+		inode->i_version ++;
+		if (inode->i_op == &udf_file_inode_operations_adinicb)
+			inode->i_op = &udf_file_inode_operations;
+		return dbh;
+	}
+	else
+		return NULL;
+}
+
+struct buffer_head * udf_getblk(struct inode * inode, long block,
+	int create, int * err)
+{
+	struct buffer_head dummy;
+	int error;
+
+	dummy.b_state = 0;
+	dummy.b_blocknr = -1000;
+	error = udf_get_block(inode, block, &dummy, create);
+	*err = error;
+	if (!error & buffer_mapped(&dummy))
+	{
+		struct buffer_head *bh;
+		bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+		if (buffer_new(&dummy))
+		{
+			memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+			mark_buffer_uptodate(bh, 1);
+			mark_buffer_dirty(bh, 1);
+		}
+		return bh;
+	}
+	return NULL;
+}
+
+int udf_get_block(struct inode *inode, long block, struct buffer_head *bh_result, int create)
+{
+	int err, new;
+	struct buffer_head *bh;
+	unsigned long phys;
+
+	if (!create)
+	{
+		phys = udf_block_map(inode, block);
+		if (phys)
+		{
+			bh_result->b_dev = inode->i_dev;
+			bh_result->b_blocknr = phys;
+			bh_result->b_state |= (1UL << BH_Mapped);
+		}
+		return 0;
+	}
+
+	err = -EIO;
+
+	lock_kernel();
+
+	if (block < 0)
+		goto abort_negative;
+
+	if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1)
+	{
+		UDF_I_NEXT_ALLOC_BLOCK(inode) ++;
+		UDF_I_NEXT_ALLOC_GOAL(inode) ++;
+	}
+
+	err = 0;
+
+	bh = inode_getblk(inode, block, &err, &phys, &new);
+	if (bh)
+		BUG();
+	if (err)
+		goto abort;
+	if (!phys)
+		BUG();
+
+	bh_result->b_dev = inode->i_dev;
+	bh_result->b_blocknr = phys;
+	bh_result->b_state |= (1UL << BH_Mapped);
+	if (new)
+		bh_result->b_state |= (1UL << BH_New);
+abort:
+	unlock_kernel();
+	return err;
+
+abort_negative:
+	udf_warning(inode->i_sb, "udf_get_block", "block < 0");
+	goto abort;
+}
+
+static struct buffer_head * inode_getblk(struct inode * inode, long block,
+	int *err, long *phys, int *new)
+{
+	struct buffer_head *pbh = NULL, *cbh = NULL, *result = NULL;
+	long_ad laarr[EXTENT_MERGE_SIZE];
+	Uint32 pextoffset = 0, cextoffset = 0, nextoffset = 0;
+	int count = 0, startnum = 0, endnum = 0;
+	Uint32 elen = 0;
+	lb_addr eloc, pbloc = UDF_I_LOCATION(inode), cbloc = UDF_I_LOCATION(inode);
+	int c = 1;
+	int lbcount = 0, b_off = 0, offset = 0;
+	Uint32 newblocknum, newblock;
+	char etype;
+	int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
+	char lastblock = 0;
+
+	pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
+	b_off = block << inode->i_sb->s_blocksize_bits;
+	pbloc = cbloc = UDF_I_LOCATION(inode);
+
+	/* find the extent which contains the block we are looking for.
+       alternate between laarr[0] and laarr[1] for locations of the
+       current extent, and the previous extent */
+	do
+	{
+		if (pbh != cbh)
+		{
+			udf_release_data(pbh);
+			atomic_inc(&cbh->b_count);
+			pbloc = cbloc;
+		}
+
+		lbcount += elen;
+
+		pextoffset = cextoffset;
+		cextoffset = nextoffset;
+	
+		if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 1)) == -1)
+			break;
+
+		c = !c;
+
+		laarr[c].extLength = (etype << 30) | elen;
+		laarr[c].extLocation = eloc;
+
+		if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+			pgoal = eloc.logicalBlockNum +
+				((elen + inode->i_sb->s_blocksize - 1) >>
+				inode->i_sb->s_blocksize);
+
+		count ++;
+	} while (lbcount + elen <= b_off);
+
+	b_off -= lbcount;
+	offset = b_off >> inode->i_sb->s_blocksize_bits;
+
+	/* if the extent is allocated and recorded, return the block
+       if the extent is not a multiple of the blocksize, round up */
+
+	if (etype == EXTENT_RECORDED_ALLOCATED)
+	{
+		if (elen & (inode->i_sb->s_blocksize - 1))
+		{
+			elen = (EXTENT_RECORDED_ALLOCATED << 30) |
+				((elen + inode->i_sb->s_blocksize - 1) &
+				~(inode->i_sb->s_blocksize - 1));
+			etype = udf_write_aext(inode, cbloc, &cextoffset, eloc, elen, &cbh, 1);
+		}
+		udf_release_data(pbh);
+		udf_release_data(cbh);
+		newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+		*phys = newblock;
+		return NULL;
+	}
+
+	if (etype == -1)
+	{
+		endnum = startnum = ((count > 1) ? 1 : count);
+		c = !c;
+		laarr[c].extLength = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+			((offset + 1) << inode->i_sb->s_blocksize_bits);
+		memset(&laarr[c].extLocation, 0x00, sizeof(lb_addr));
+		count ++;
+		endnum ++;
+		lastblock = 1;
+	}
+	else
+		endnum = startnum = ((count > 2) ? 2 : count);
+
+	/* if the current extent is in position 0, swap it with the previous */
+	if (!c && count != 1)
+	{
+		laarr[2] = laarr[0];
+		laarr[0] = laarr[1];
+		laarr[1] = laarr[2];
+		c = 1;
+	}
+
+	/* if the current block is located in a extent, read the next extent */
+	if (etype != -1)
+	{
+		if ((etype = udf_next_aext(inode, &cbloc, &nextoffset, &eloc, &elen, &cbh, 0)) != -1)
+		{
+			laarr[c+1].extLength = (etype << 30) | elen;
+			laarr[c+1].extLocation = eloc;
+			count ++;
+			startnum ++;
+			endnum ++;
+		}
+		else
+			lastblock = 1;
+	}
+	udf_release_data(cbh);
+
+	*err = -EFBIG;
+
+	/* Check file limits.. */
+	{
+		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+		if (limit < RLIM_INFINITY)
+		{
+			limit >>= inode->i_sb->s_blocksize_bits;
+			if (block >= limit)
+			{
+				send_sig(SIGXFSZ, current, 0);
+				*err = -EFBIG;
+				return NULL;
+			}
+		}
+	}
+
+	/* if the current extent is not recorded but allocated, get the
+       block in the extent corresponding to the requested block */
+	if ((laarr[c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+		newblocknum = laarr[c].extLocation.logicalBlockNum + offset;
+	else /* otherwise, allocate a new block */
+	{
+		if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)
+			goal = UDF_I_NEXT_ALLOC_GOAL(inode);
+
+		if (!goal)
+		{
+			if (!(goal = pgoal))
+				goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
+		}
+
+		if (!(newblocknum = udf_alloc_block(inode,
+			UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
+		{
+			udf_release_data(pbh);
+			udf_release_data(cbh);
+			*err = -ENOSPC;
+			return NULL;
+		}
+	}
+
+	/* if the extent the requsted block is located in contains multiple blocks,
+       split the extent into at most three extents. blocks prior to requested
+       block, requested block, and blocks after requested block */
+	udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
+
+#ifdef UDF_PREALLOCATE
+	/* preallocate blocks */
+	udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
+#endif
+
+	/* merge any continuous blocks in laarr */
+	udf_merge_extents(inode, laarr, &endnum);
+
+	/* write back the new extents, inserting new extents if the new number
+       of extents is greater than the old number, and deleting extents if
+       the new number of extents is less than the old number */
+	udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);
+
+	udf_release_data(pbh);
+
+	if (c == 0 || c == 1)
+	{
+		UDF_I_EXT0LEN(inode) = laarr[0].extLength;
+		UDF_I_EXT0LOC(inode) = laarr[0].extLocation;
+	}
+
+	if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
+		UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
+	{
+		return NULL;
+	}
+	*phys = newblock;
+	*err = 0;
+	*new = 1;
+	UDF_I_NEXT_ALLOC_BLOCK(inode) = block;
+	UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum;
+	inode->i_ctime = CURRENT_TIME;
+	UDF_I_UCTIME(inode) = CURRENT_UTIME;
+	inode->i_blocks += inode->i_sb->s_blocksize / 512;
+#if 0
+	if (IS_SYNC(inode) || UDF_I_OSYNC(inode))
+		udf_sync_inode(inode);
+	else
+#endif
+		mark_inode_dirty(inode);
+	return result;
+}
+
+static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum,
+	long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+{
+	if ((laarr[*c].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED ||
+		(laarr[*c].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+	{
+		int curr = *c;
+		int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
+			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+		int type = laarr[curr].extLength & ~UDF_EXTENT_LENGTH_MASK;
+
+		if (blen == 1)
+			;
+		else if (!offset || blen == offset + 1)
+		{
+			laarr[curr+2] = laarr[curr+1];
+			laarr[curr+1] = laarr[curr];
+		}
+		else
+		{
+			laarr[curr+3] = laarr[curr+1];
+			laarr[curr+2] = laarr[curr+1] = laarr[curr];
+		}
+
+		if (offset)
+		{
+			laarr[curr].extLength = type |
+				(offset << inode->i_sb->s_blocksize_bits);
+			curr ++;
+			(*c) ++;
+			(*endnum) ++;
+		}
+		
+		laarr[curr].extLocation.logicalBlockNum = newblocknum;
+		if ((type >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+			laarr[curr].extLocation.partitionReferenceNum =
+				UDF_I_LOCATION(inode).partitionReferenceNum;
+		laarr[curr].extLength = (EXTENT_RECORDED_ALLOCATED << 30) |
+			inode->i_sb->s_blocksize;
+		curr ++;
+
+		if (blen != offset + 1)
+		{
+			if ((type >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+				laarr[curr].extLocation.logicalBlockNum += (offset + 1);
+			laarr[curr].extLength = type |
+				((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
+			curr ++;
+			(*endnum) ++;
+		}
+	}
+}
+
+static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
+	 long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+{
+	int start, length = 0, currlength = 0, i;
+
+	if (*endnum == (c+1) && !lastblock)
+		return;
+
+	if ((laarr[c+1].extLength >> 30) == EXTENT_NOT_RECORDED_ALLOCATED)
+	{
+		start = c+1;
+		length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
+			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+	}
+	else
+		start = c;
+
+	for (i=start+1; i<=*endnum; i++)
+	{
+		if (i == *endnum)
+		{
+			if (lastblock)
+				length += UDF_DEFAULT_PREALLOC_BLOCKS;
+		}
+		else if ((laarr[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+			length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+		else
+			break;
+	}
+
+	if (length)
+	{
+		int next = laarr[start].extLocation.logicalBlockNum +
+			(((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
+			inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+		int numalloc = udf_alloc_blocks(inode,
+			laarr[start].extLocation.partitionReferenceNum,
+			next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
+				UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
+
+		if (numalloc)
+		{
+			if (start == (c+1))
+				laarr[start].extLength +=
+					(numalloc << inode->i_sb->s_blocksize_bits);
+			else
+			{
+				memmove(&laarr[c+2], &laarr[c+1],
+					sizeof(long_ad) * (*endnum - (c+1)));
+				(*endnum) ++;
+				laarr[c+1].extLocation.logicalBlockNum = next;
+				laarr[c+1].extLocation.partitionReferenceNum =
+					laarr[c].extLocation.partitionReferenceNum;
+				laarr[c+1].extLength = (EXTENT_NOT_RECORDED_ALLOCATED << 30) |
+					(numalloc << inode->i_sb->s_blocksize_bits);
+				start = c+1;
+			}
+
+			for (i=start+1; numalloc && i<*endnum; i++)
+			{
+				int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+
+				if (elen > numalloc)
+				{
+					laarr[c+1].extLength -=
+						(numalloc << inode->i_sb->s_blocksize_bits);
+					numalloc = 0;
+				}
+				else
+				{
+					numalloc -= elen;
+					if (*endnum > (i+1))
+						memmove(&laarr[i], &laarr[i+1], 
+							sizeof(long_ad) * (*endnum - (i+1)));
+					i --;
+					(*endnum) --;
+				}
+			}
+		}
+	}
+}
+
+static void udf_merge_extents(struct inode *inode,
+	 long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+{
+	int i;
+
+	for (i=0; i<(*endnum-1); i++)
+	{
+		if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30))
+		{
+			if (((laarr[i].extLength >> 30) == EXTENT_NOT_RECORDED_NOT_ALLOCATED) ||
+				((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
+				(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+				inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits)))
+			{
+				laarr[i].extLength = laarr[i+1].extLength +
+					(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+					inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
+				if (*endnum > (i+2))
+					memmove(&laarr[i+1], &laarr[i+2],
+						sizeof(long_ad) * (*endnum - (i+2)));
+				i --;
+				(*endnum) --;
+			}
+		}
+	}
+}
+
+static void udf_update_extents(struct inode *inode,
+	long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
+	lb_addr pbloc, Uint32 pextoffset, struct buffer_head **pbh)
+{
+	int start = 0, i;
+	lb_addr tmploc;
+	Uint32 tmplen;
+
+	if (startnum > endnum)
+	{
+		for (i=0; i<(startnum-endnum); i++)
+		{
+			udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
+				laarr[i].extLength, *pbh);
+		}
+	}
+	else if (startnum < endnum)
+	{
+		for (i=0; i<(endnum-startnum); i++)
+		{
+			udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
+				laarr[i].extLength, *pbh);
+			udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation,
+				&laarr[i].extLength, pbh, 1);
+			start ++;
+		}
+	}
+
+	for (i=start; i<endnum; i++)
+	{
+		udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
+		udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
+			laarr[i].extLength, pbh, 1);
+	}
+}
+
+struct buffer_head * udf_bread(struct inode * inode, int block,
+	int create, int * err)
+{
+	struct buffer_head * bh = NULL;
+	int prev_blocks;
+
+	prev_blocks = inode->i_blocks;
+
+	bh = udf_getblk(inode, block, create, err);
+	if (!bh)
+		return NULL;
+
+#if 0
+	if (create &&
+		S_ISDIR(inode->i_mode) &&
+		inode->i_blocks > prev_blocks)
+	{
+		int i;
+		struct buffer_head *tmp_bh = NULL;
+
+		for (i=1;
+			i < UDF_DEFAULT_PREALLOC_DIR_BLOCKS;
+			i++)
+		{
+			tmp_bh = udf_getblk(inode, block+i, create, err);
+			if (!tmp_bh)
+			{
+				udf_release_data(bh);
+				return 0;
+			}
+			udf_release_data(tmp_bh);
+		}
+	}
+#endif
+
+	if (buffer_uptodate(bh))
+		return bh;
+	ll_rw_block(READ, 1, &bh);
+	wait_on_buffer(bh);
+	if (buffer_uptodate(bh))
+		return bh;
+	brelse(bh);
+	*err = -EIO;
+	return NULL;
+}
+
+/*
+ * udf_read_inode
+ *
+ * PURPOSE
+ *	Read an inode.
+ *
+ * DESCRIPTION
+ *	This routine is called by iget() [which is called by udf_iget()]
+ *      (clean_inode() will have been called first)
+ *	when an inode is first read into memory.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ *
+ * 12/19/98 dgb  Updated to fix size problems.
+ */
+void
+udf_read_inode(struct inode *inode)
+{
+	struct buffer_head *bh = NULL;
+	struct FileEntry *fe;
+	Uint16 ident;
+
+	/*
+	 * Set defaults, but the inode is still incomplete!
+	 * Note: get_new_inode() sets the following on a new inode:
+	 *      i_sb = sb
+	 *      i_dev = sb->s_dev;
+	 *      i_no = ino
+	 *      i_flags = sb->s_flags
+	 *      i_state = 0
+	 * clean_inode(): zero fills and sets
+	 *      i_count = 1
+	 *      i_nlink = 1
+	 *      i_op = NULL;
+	 */
+
+	inode->i_blksize = inode->i_sb->s_blocksize;
+	inode->i_version = 1;
+
+	UDF_I_EXT0LEN(inode)=0;
+	UDF_I_EXT0LOC(inode).logicalBlockNum = 0xFFFFFFFF;
+	UDF_I_EXT0LOC(inode).partitionReferenceNum = 0xFFFF;
+	UDF_I_EXT0OFFS(inode)=0;
+	UDF_I_ALLOCTYPE(inode)=0;
+
+	memcpy(&UDF_I_LOCATION(inode), &UDF_SB_LOCATION(inode->i_sb), sizeof(lb_addr));
+
+	bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
+
+	if (!bh)
+	{
+		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
+			inode->i_ino);
+		make_bad_inode(inode);
+		return;
+	}
+
+	if (ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY)
+	{
+		printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
+			inode->i_ino, ident);
+		udf_release_data(bh);
+		make_bad_inode(inode);
+		return;
+	}
+
+	fe = (struct FileEntry *)bh->b_data;
+
+	if (le16_to_cpu(fe->icbTag.strategyType) == 4096)
+	{
+		struct buffer_head *ibh = NULL, *nbh = NULL;
+		struct IndirectEntry *ie;
+
+		ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident);
+		if (ident == TID_INDIRECT_ENTRY)
+		{
+			if (ibh)
+			{
+				lb_addr loc;
+				ie = (struct IndirectEntry *)ibh->b_data;
+	
+				loc = lelb_to_cpu(ie->indirectICB.extLocation);
+	
+				if (ie->indirectICB.extLength && 
+					(nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
+				{
+					if (ident == TID_FILE_ENTRY ||
+						ident == TID_EXTENDED_FILE_ENTRY)
+					{
+						memcpy(&UDF_SB_LOCATION(inode->i_sb), &loc, sizeof(lb_addr));
+						udf_release_data(bh);
+						udf_release_data(ibh);
+						udf_release_data(nbh);
+						udf_read_inode(inode);
+						return;
+					}
+					else
+					{
+						udf_release_data(nbh);
+						udf_release_data(ibh);
+					}
+				}
+				else
+					udf_release_data(ibh);
+			}
+		}
+		else
+			udf_release_data(ibh);
+	}
+	else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
+	{
+		printk(KERN_ERR "udf: unsupported strategy type: %d\n",
+			le16_to_cpu(fe->icbTag.strategyType));
+		udf_release_data(bh);
+		make_bad_inode(inode);
+		return;
+	}
+	udf_fill_inode(inode, bh);
+	udf_release_data(bh);
+}
+
+static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
+{
+	struct FileEntry *fe;
+	struct ExtendedFileEntry *efe;
+    time_t convtime;
+	int offset, alen;
+
+	fe = (struct FileEntry *)bh->b_data;
+	efe = (struct ExtendedFileEntry *)bh->b_data;
+
+	if (fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY)
+		UDF_I_EXTENDED_FE(inode) = 1;
+	else /* fe->descTag.tagIdent == TID_FILE_ENTRY */
+		UDF_I_EXTENDED_FE(inode) = 0;
+
+	if (le16_to_cpu(fe->icbTag.strategyType) == 4)
+		UDF_I_STRAT4096(inode) = 0;
+	else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */
+		UDF_I_STRAT4096(inode) = 1;
+
+	inode->i_uid = udf_convert_uid(le32_to_cpu(fe->uid));
+	if ( !inode->i_uid ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
+
+	inode->i_gid = udf_convert_gid(le32_to_cpu(fe->gid));
+	if ( !inode->i_gid ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
+
+	inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
+	if (!inode->i_nlink)
+		inode->i_nlink = 1;
+	
+	inode->i_size = le64_to_cpu(fe->informationLength);
+#if BITS_PER_LONG < 64
+	if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000)
+		inode->i_size = (Uint32)-1;
+#endif
+
+	inode->i_mode = udf_convert_permissions(fe);
+	inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
+
+#ifdef UDF_PREALLOCATE
+#if 0
+	UDF_I_PREALLOC_BLOCK(inode) = 0;
+	UDF_I_PREALLOC_COUNT(inode) = 0;
+#endif
+#endif
+	UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
+	UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
+
+	UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICB_FLAG_ALLOC_MASK;
+
+	if (UDF_I_EXTENDED_FE(inode) == 0)
+	{
+		inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
+			(inode->i_sb->s_blocksize_bits - 9);
+
+		if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->modificationTime)) )
+		{
+			inode->i_mtime = convtime;
+			inode->i_ctime = convtime;
+		}
+		else
+		{
+			inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
+			inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
+		}
+
+		if ( udf_stamp_to_time(&convtime, lets_to_cpu(fe->accessTime)) ) 
+			inode->i_atime = convtime;
+		else
+			inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
+
+		UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID);
+		UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
+		UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs);
+		offset = sizeof(struct FileEntry) + UDF_I_LENEATTR(inode);
+		alen = offset + UDF_I_LENALLOC(inode);
+	}
+	else
+	{
+		inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << 
+			(inode->i_sb->s_blocksize_bits - 9);
+
+		if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->modificationTime)) )
+			inode->i_mtime = convtime;
+		else
+			inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
+
+		if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->accessTime)) )
+			inode->i_atime = convtime;
+		else
+			inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
+
+		if ( udf_stamp_to_time(&convtime, lets_to_cpu(efe->createTime)) )
+			inode->i_ctime = convtime;
+		else
+			inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
+
+		UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID);
+		UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr);
+		UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs);
+		offset = sizeof(struct ExtendedFileEntry) + UDF_I_LENEATTR(inode);
+		alen = offset + UDF_I_LENALLOC(inode);
+	}
+
+	switch (UDF_I_ALLOCTYPE(inode))
+	{
+		case ICB_FLAG_AD_SHORT:
+ 		{
+ 			short_ad * sa;
+
+			sa = udf_get_fileshortad(fe, alen, &offset, 1);
+			if (sa)
+			{
+				UDF_I_EXT0LEN(inode) = le32_to_cpu(sa->extLength);
+ 				UDF_I_EXT0LOC(inode).logicalBlockNum = le32_to_cpu(sa->extPosition);
+				UDF_I_EXT0LOC(inode).partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+			}
+			break;
+ 		}
+		case ICB_FLAG_AD_LONG:
+		{
+		    long_ad * la;
+
+		    la = udf_get_filelongad(fe, alen, &offset, 1);
+		    if (la)
+			{
+				UDF_I_EXT0LEN(inode) = le32_to_cpu(la->extLength);
+				UDF_I_EXT0LOC(inode).logicalBlockNum = le32_to_cpu(la->extLocation.logicalBlockNum);
+				UDF_I_EXT0LOC(inode).partitionReferenceNum = le16_to_cpu(la->extLocation.partitionReferenceNum);
+		    }
+			break;
+		}
+		case ICB_FLAG_AD_EXTENDED:
+		{
+			extent_ad * ext;
+
+		    ext = udf_get_fileextent(fe, alen, &offset);
+		    if ( (ext) && (ext->extLength) )
+			{
+				UDF_I_EXT0LEN(inode) = le32_to_cpu(ext->extLength);
+#if 0
+				UDF_I_EXT0LOC(inode) = ext->extLocation;
+#endif
+			}
+			break;
+		}
+		case ICB_FLAG_AD_IN_ICB: /* short directories */
+		{
+			UDF_I_EXT0LEN(inode) = le32_to_cpu(fe->lengthAllocDescs);
+			UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode);
+			UDF_I_EXT0OFFS(inode) = sizeof(struct FileEntry) +
+				le32_to_cpu(fe->lengthExtendedAttr);
+			break;
+		}
+	} /* end switch ad_type */
+
+	switch (fe->icbTag.fileType)
+	{
+		case FILE_TYPE_DIRECTORY:
+		{
+			inode->i_op = &udf_dir_inode_operations;
+			inode->i_mode |= S_IFDIR;
+			inode->i_nlink ++;
+			break;
+		}
+		case FILE_TYPE_REGULAR:
+		case FILE_TYPE_NONE:
+		{
+			if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+				inode->i_op = &udf_file_inode_operations_adinicb;
+			else
+				inode->i_op = &udf_file_inode_operations;
+			inode->i_mode |= S_IFREG;
+			break;
+		}
+		case FILE_TYPE_BLOCK:
+		{
+			inode->i_op = &blkdev_inode_operations;
+			inode->i_mode |= S_IFBLK;
+			break;
+		}
+		case FILE_TYPE_CHAR:
+		{
+			inode->i_op = &chrdev_inode_operations;
+			inode->i_mode |= S_IFCHR;
+			break;
+		}
+		case FILE_TYPE_FIFO:
+		{
+			init_fifo(inode);
+		}
+		case FILE_TYPE_SYMLINK:
+		{
+			/* untested! */
+			inode->i_op = &udf_symlink_inode_operations;
+			inode->i_mode = S_IFLNK|S_IRWXUGO;
+			break;
+		}
+		default:
+		{
+			printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
+				inode->i_ino, fe->icbTag.fileType);
+			make_bad_inode(inode);
+			return;
+		}
+	}
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+	{
+		struct buffer_head *tbh = NULL;
+		struct DeviceSpecificationExtendedAttr *dsea =
+			(struct DeviceSpecificationExtendedAttr *)
+				udf_get_extendedattr(inode, 12, 1, &tbh);
+
+		if (dsea)
+		{
+			inode->i_rdev = to_kdev_t(
+				(le32_to_cpu(dsea->majorDeviceIdent)) << 8) |
+				(le32_to_cpu(dsea->minorDeviceIdent) & 0xFF);
+			/* Developer ID ??? */
+			udf_release_data(tbh);
+		}
+		else
+		{
+			make_bad_inode(inode);
+		}
+	}
+}
+
+static mode_t
+udf_convert_permissions(struct FileEntry *fe)
+{
+	mode_t mode;
+	Uint32 permissions;
+	Uint32 flags;
+
+	permissions = le32_to_cpu(fe->permissions);
+	flags = le16_to_cpu(fe->icbTag.flags);
+
+	mode =	(( permissions      ) & S_IRWXO) |
+			(( permissions >> 2 ) & S_IRWXG) |
+			(( permissions >> 4 ) & S_IRWXU) |
+			(( flags & ICB_FLAG_SETUID) ? S_ISUID : 0) |
+			(( flags & ICB_FLAG_SETGID) ? S_ISGID : 0) |
+			(( flags & ICB_FLAG_STICKY) ? S_ISVTX : 0);
+
+	return mode;
+}
+
+/*
+ * udf_write_inode
+ *
+ * PURPOSE
+ *	Write out the specified inode.
+ *
+ * DESCRIPTION
+ *	This routine is called whenever an inode is synced.
+ *	Currently this routine is just a placeholder.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+
+void udf_write_inode(struct inode * inode)
+{
+	udf_update_inode(inode, 0);
+}
+
+int udf_sync_inode(struct inode * inode)
+{
+	return udf_update_inode(inode, 1);
+}
+
+static int
+udf_update_inode(struct inode *inode, int do_sync)
+{
+	struct buffer_head *bh = NULL;
+	struct FileEntry *fe;
+	struct ExtendedFileEntry *efe;
+	Uint32 udfperms;
+	Uint16 icbflags;
+	Uint16 crclen;
+	int i;
+	timestamp cpu_time;
+	int err = 0;
+
+	bh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0),
+			inode->i_sb->s_blocksize);
+	if (!bh)
+	{
+		udf_debug("bread failure\n");
+		return -EIO;
+	}
+	fe = (struct FileEntry *)bh->b_data;
+	efe = (struct ExtendedFileEntry *)bh->b_data;
+
+	if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
+		fe->uid = cpu_to_le32(inode->i_uid);
+
+	if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
+		fe->gid = cpu_to_le32(inode->i_gid);
+
+	udfperms =  ((inode->i_mode & S_IRWXO)     ) |
+				((inode->i_mode & S_IRWXG) << 2) |
+				((inode->i_mode & S_IRWXU) << 4);
+
+	udfperms |= (le32_to_cpu(fe->permissions) &
+		(PERM_O_DELETE | PERM_O_CHATTR |
+		 PERM_G_DELETE | PERM_G_CHATTR |
+		 PERM_U_DELETE | PERM_U_CHATTR));
+	fe->permissions = cpu_to_le32(udfperms);
+
+	if (S_ISDIR(inode->i_mode))
+		fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1);
+	else
+		fe->fileLinkCount = cpu_to_le16(inode->i_nlink);
+
+
+	fe->informationLength = cpu_to_le64(inode->i_size);
+
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+	{
+		EntityID *eid;
+		struct buffer_head *tbh = NULL;
+		struct DeviceSpecificationExtendedAttr *dsea =
+			(struct DeviceSpecificationExtendedAttr *)
+				udf_get_extendedattr(inode, 12, 1, &tbh);	
+
+		if (!dsea)
+		{
+			dsea = (struct DeviceSpecificationExtendedAttr *)
+				udf_add_extendedattr(inode,
+					sizeof(struct DeviceSpecificationExtendedAttr) +
+					sizeof(EntityID), 12, 0x3, &tbh);
+			dsea->attrType = 12;
+			dsea->attrSubtype = 1;
+			dsea->attrLength = sizeof(struct DeviceSpecificationExtendedAttr) +
+				sizeof(EntityID);
+			dsea->impUseLength = sizeof(EntityID);
+		}
+		eid = (EntityID *)dsea->impUse;
+		memset(eid, 0, sizeof(EntityID));
+		strcpy(eid->ident, UDF_ID_DEVELOPER);
+		eid->identSuffix[0] = UDF_OS_CLASS_UNIX;
+		eid->identSuffix[1] = UDF_OS_ID_LINUX;
+		dsea->majorDeviceIdent = kdev_t_to_nr(inode->i_rdev) >> 8;
+		dsea->minorDeviceIdent = kdev_t_to_nr(inode->i_rdev) & 0xFF;
+		mark_buffer_dirty(tbh, 1);
+		udf_release_data(tbh);
+	}
+
+	if (UDF_I_EXTENDED_FE(inode) == 0)
+	{
+		fe->logicalBlocksRecorded = cpu_to_le64(
+			(inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
+			(inode->i_sb->s_blocksize_bits - 9));
+
+		if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode)))
+			fe->accessTime = cpu_to_lets(cpu_time);
+		if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode)))
+			fe->modificationTime = cpu_to_lets(cpu_time);
+		memset(&(fe->impIdent), 0, sizeof(EntityID));
+		strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
+		fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+		fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+		fe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
+		fe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
+		fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+		fe->descTag.tagIdent = le16_to_cpu(TID_FILE_ENTRY);
+		crclen = sizeof(struct FileEntry);
+	}
+	else
+	{
+		efe->logicalBlocksRecorded = cpu_to_le64(
+			(inode->i_blocks + (2 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
+			(inode->i_sb->s_blocksize_bits - 9));
+
+		if (udf_time_to_stamp(&cpu_time, inode->i_atime, UDF_I_UATIME(inode)))
+			efe->accessTime = cpu_to_lets(cpu_time);
+		if (udf_time_to_stamp(&cpu_time, inode->i_mtime, UDF_I_UMTIME(inode)))
+			efe->modificationTime = cpu_to_lets(cpu_time);
+		if (udf_time_to_stamp(&cpu_time, inode->i_ctime, UDF_I_UCTIME(inode)))
+			efe->createTime = cpu_to_lets(cpu_time);
+		memset(&(efe->impIdent), 0, sizeof(EntityID));
+		strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
+		efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+		efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+		efe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
+        efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
+        efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+		efe->descTag.tagIdent = le16_to_cpu(TID_EXTENDED_FILE_ENTRY);
+		crclen = sizeof(struct ExtendedFileEntry);
+	}
+	fe->icbTag.strategyType = UDF_I_STRAT4096(inode) ? cpu_to_le16(4096) :
+		cpu_to_le16(4);
+
+	if (S_ISDIR(inode->i_mode))
+		fe->icbTag.fileType = FILE_TYPE_DIRECTORY;
+	else if (S_ISREG(inode->i_mode))
+		fe->icbTag.fileType = FILE_TYPE_REGULAR;
+	else if (S_ISLNK(inode->i_mode))
+		fe->icbTag.fileType = FILE_TYPE_SYMLINK;
+	else if (S_ISBLK(inode->i_mode))
+		fe->icbTag.fileType = FILE_TYPE_BLOCK;
+	else if (S_ISCHR(inode->i_mode))
+		fe->icbTag.fileType = FILE_TYPE_CHAR;
+	else if (S_ISFIFO(inode->i_mode))
+		fe->icbTag.fileType = FILE_TYPE_FIFO;
+
+	icbflags = UDF_I_ALLOCTYPE(inode) |
+			((inode->i_mode & S_ISUID) ? ICB_FLAG_SETUID : 0) |
+			((inode->i_mode & S_ISGID) ? ICB_FLAG_SETGID : 0) |
+			((inode->i_mode & S_ISVTX) ? ICB_FLAG_STICKY : 0) |
+			(le16_to_cpu(fe->icbTag.flags) &
+				~(ICB_FLAG_ALLOC_MASK | ICB_FLAG_SETUID |
+				ICB_FLAG_SETGID | ICB_FLAG_STICKY));
+
+	fe->icbTag.flags = cpu_to_le16(icbflags);
+	fe->descTag.descVersion = cpu_to_le16(2);
+	fe->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
+	fe->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+	crclen += UDF_I_LENEATTR(inode) + UDF_I_LENALLOC(inode) - sizeof(tag);
+	fe->descTag.descCRCLength = cpu_to_le16(crclen);
+	fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
+
+	fe->descTag.tagChecksum = 0;
+	for (i=0; i<16; i++)
+		if (i != 4)
+			fe->descTag.tagChecksum += ((Uint8 *)&(fe->descTag))[i];
+
+	/* write the data blocks */
+	mark_buffer_dirty(bh, 1);
+	if (do_sync)
+	{
+		ll_rw_block(WRITE, 1, &bh);
+		wait_on_buffer(bh);
+		if (buffer_req(bh) && !buffer_uptodate(bh))
+		{
+			printk("IO error syncing udf inode [%s:%08lx]\n",
+				bdevname(inode->i_dev), inode->i_ino);
+			err = -EIO;
+		}
+	}
+	udf_release_data(bh);
+	return err;
+}
+
+/*
+ * udf_iget
+ *
+ * PURPOSE
+ *	Get an inode.
+ *
+ * DESCRIPTION
+ *	This routine replaces iget() and read_inode().
+ *
+ * HISTORY
+ *	October 3, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ *
+ * 12/19/98 dgb  Added semaphore and changed to be a wrapper of iget
+ */
+struct inode *
+udf_iget(struct super_block *sb, lb_addr ino)
+{
+	struct inode *inode;
+	unsigned long block;
+
+	block = udf_get_lb_pblock(sb, ino, 0);
+
+	down(&read_semaphore); /* serialize access to UDF_SB_LOCATION() */
+	/* This is really icky.. should fix -- blf */
+
+	/* put the location where udf_read_inode can find it */
+	memcpy(&UDF_SB_LOCATION(sb), &ino, sizeof(lb_addr));
+
+	/* Get the inode */
+
+	inode = iget(sb, block);
+		/* calls udf_read_inode() ! */
+
+	up(&read_semaphore);
+
+	if (!inode)
+	{
+		printk(KERN_ERR "udf: iget() failed\n");
+		return NULL;
+	}
+	else if (is_bad_inode(inode))
+	{
+		iput(inode);
+		return NULL;
+	}
+
+	if ( ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum) )
+	{
+		udf_debug("block=%d, partition=%d out of range\n",
+			ino.logicalBlockNum, ino.partitionReferenceNum);
+		return NULL;
+ 	}
+
+	return inode;
+}
+
+int udf_add_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+	lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc)
+{
+	int adsize;
+	short_ad *sad = NULL;
+	long_ad *lad = NULL;
+	struct AllocExtDesc *aed;
+	int ret;
+
+	if (!(*bh))
+	{
+		if (!(*bh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, *bloc, 0),
+			inode->i_sb->s_blocksize)))
+		{
+			udf_debug("reading block %d failed!\n",
+				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+			return -1;
+		}
+	}
+
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		return -1;
+
+	if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize)
+	{
+		char *sptr, *dptr;
+		struct buffer_head *nbh;
+		int err, loffset;
+		Uint32	lblock = bloc->logicalBlockNum;
+		Uint16  lpart = bloc->partitionReferenceNum;
+
+		if (!(bloc->logicalBlockNum = udf_new_block(inode,
+			lpart, lblock, &err)))
+		{
+			return -1;
+		}
+		if (!(nbh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
+			*bloc, 0), inode->i_sb->s_blocksize)))
+		{
+			return -1;
+		}
+		aed = (struct AllocExtDesc *)(nbh->b_data);
+		aed->previousAllocExtLocation = cpu_to_le32(lblock);
+		if (*extoffset + adsize > inode->i_sb->s_blocksize)
+		{
+			loffset = *extoffset;
+			aed->lengthAllocDescs = cpu_to_le32(adsize);
+			sptr = (*bh)->b_data + *extoffset - adsize;
+			dptr = nbh->b_data + sizeof(struct AllocExtDesc);
+			memcpy(dptr, sptr, adsize);
+			*extoffset = sizeof(struct AllocExtDesc) + adsize;
+		}
+		else
+		{
+			loffset = *extoffset + adsize;
+			aed->lengthAllocDescs = cpu_to_le32(0);
+			sptr = (*bh)->b_data + *extoffset;
+			*extoffset = sizeof(struct AllocExtDesc);
+
+			if (UDF_I_LOCATION(inode).logicalBlockNum == lblock)
+				UDF_I_LENALLOC(inode) += adsize;
+			else
+			{
+				aed = (struct AllocExtDesc *)(*bh)->b_data;
+				aed->lengthAllocDescs =
+					cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+			}
+		}
+		udf_new_tag(nbh->b_data, TID_ALLOC_EXTENT_DESC, 2, 1,
+			bloc->logicalBlockNum, sizeof(tag));
+		switch (UDF_I_ALLOCTYPE(inode))
+		{
+			case ICB_FLAG_AD_SHORT:
+			{
+				sad = (short_ad *)sptr;
+				sad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+					inode->i_sb->s_blocksize;
+				sad->extPosition = cpu_to_le32(bloc->logicalBlockNum);
+				break;
+			}
+			case ICB_FLAG_AD_LONG:
+			{
+				lad = (long_ad *)sptr;
+				lad->extLength = EXTENT_NEXT_EXTENT_ALLOCDECS << 30 |
+					inode->i_sb->s_blocksize;
+				lad->extLocation = cpu_to_lelb(*bloc);
+				break;
+			}
+		}
+		udf_update_tag((*bh)->b_data, loffset);
+		mark_buffer_dirty(*bh, 1);
+		udf_release_data(*bh);
+		*bh = nbh;
+	}
+
+	ret = udf_write_aext(inode, *bloc, extoffset, eloc, elen, bh, inc);
+
+	if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
+	{
+		UDF_I_LENALLOC(inode) += adsize;
+		mark_inode_dirty(inode);
+	}
+	else
+	{
+		aed = (struct AllocExtDesc *)(*bh)->b_data;
+		aed->lengthAllocDescs =
+			cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
+		udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
+		mark_buffer_dirty(*bh, 1);
+	}
+
+	return ret;
+}
+
+int udf_write_aext(struct inode *inode, lb_addr bloc, int *extoffset,
+    lb_addr eloc, Uint32 elen, struct buffer_head **bh, int inc)
+{
+	int adsize;
+	short_ad *sad = NULL;
+	long_ad *lad = NULL;
+
+    if (!(*bh))
+	{
+		if (!(*bh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, bloc, 0),
+			inode->i_sb->s_blocksize)))
+		{
+			udf_debug("reading block %d failed!\n",
+				udf_get_lb_pblock(inode->i_sb, bloc, 0));
+			return -1;
+		}
+	}
+
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		return -1;
+
+	switch (UDF_I_ALLOCTYPE(inode))
+	{
+		case ICB_FLAG_AD_SHORT:
+		{
+			sad = (short_ad *)((*bh)->b_data + *extoffset);
+			sad->extLength = cpu_to_le32(elen);
+			sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
+			break;
+		}
+		case ICB_FLAG_AD_LONG:
+		{
+			lad = (long_ad *)((*bh)->b_data + *extoffset);
+			lad->extLength = cpu_to_le32(elen);
+			lad->extLocation = cpu_to_lelb(eloc);
+			break;
+		}
+	}
+
+	if (memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+	{
+		struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
+		udf_update_tag((*bh)->b_data,
+			le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct AllocExtDesc));
+	}
+
+	mark_buffer_dirty(*bh, 1);
+
+	if (inc)
+		*extoffset += adsize;
+	return (elen >> 30);
+}
+
+int udf_next_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+	lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
+{
+	int pos, alen;
+	Uint8 etype;
+
+	if (!(*bh))
+	{
+		if (!(*bh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, *bloc, 0),
+			inode->i_sb->s_blocksize)))
+		{
+			udf_debug("reading block %d failed!\n",
+				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+			return -1;
+		}
+	}
+
+	if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
+	{
+		pos = udf_file_entry_alloc_offset(inode);
+		alen = UDF_I_LENALLOC(inode) + pos;
+	}
+	else
+	{
+		struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
+
+		pos = sizeof(struct AllocExtDesc);
+		alen = le32_to_cpu(aed->lengthAllocDescs) + pos;
+	}
+
+	if (!(*extoffset))
+		*extoffset = pos;
+
+	switch (UDF_I_ALLOCTYPE(inode))
+	{
+		case ICB_FLAG_AD_SHORT:
+		{
+			short_ad *sad;
+
+			if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc)))
+				return -1;
+
+			if ((etype = le32_to_cpu(sad->extLength) >> 30) == EXTENT_NEXT_EXTENT_ALLOCDECS)
+			{
+				bloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+				*extoffset = 0;
+				udf_release_data(*bh);
+				*bh = NULL;
+				return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc);
+			}
+			else
+			{
+				eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+				eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+				*elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+			}
+			break;
+		}
+		case ICB_FLAG_AD_LONG:
+		{
+			long_ad *lad;
+
+			if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc)))
+				return -1;
+
+			if ((etype = le32_to_cpu(lad->extLength) >> 30) == EXTENT_NEXT_EXTENT_ALLOCDECS)
+			{
+				*bloc = lelb_to_cpu(lad->extLocation);
+				*extoffset = 0;
+				udf_release_data(*bh);
+				*bh = NULL;
+				return udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, inc);
+			}
+			else
+			{
+				*eloc = lelb_to_cpu(lad->extLocation);
+				*elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+			}
+			break;
+		}
+		default:
+		{
+			udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+			return -1;
+		}
+	}
+	if (*elen)
+		return etype;
+
+	udf_debug("Empty Extent!\n");
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		*extoffset -= sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		*extoffset -= sizeof(long_ad);
+	return -1;
+}
+
+int udf_current_aext(struct inode *inode, lb_addr *bloc, int *extoffset,
+	lb_addr *eloc, Uint32 *elen, struct buffer_head **bh, int inc)
+{
+	int pos, alen;
+	Uint8 etype;
+
+	if (!(*bh))
+	{
+		if (!(*bh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, *bloc, 0),
+			inode->i_sb->s_blocksize)))
+		{
+			udf_debug("reading block %d failed!\n",
+				udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+			return -1;
+		}
+	}
+
+	if (!memcmp(&UDF_I_LOCATION(inode), bloc, sizeof(lb_addr)))
+	{
+		if (!(UDF_I_EXTENDED_FE(inode)))
+			pos = sizeof(struct FileEntry) + UDF_I_LENEATTR(inode);
+		else
+			pos = sizeof(struct ExtendedFileEntry) + UDF_I_LENEATTR(inode);
+		alen = UDF_I_LENALLOC(inode) + pos;
+	}
+	else
+	{
+		struct AllocExtDesc *aed = (struct AllocExtDesc *)(*bh)->b_data;
+
+		pos = sizeof(struct AllocExtDesc);
+		alen = le32_to_cpu(aed->lengthAllocDescs) + pos;
+	}
+
+	if (!(*extoffset))
+		*extoffset = pos;
+
+	switch (UDF_I_ALLOCTYPE(inode))
+	{
+		case ICB_FLAG_AD_SHORT:
+		{
+			short_ad *sad;
+
+			if (!(sad = udf_get_fileshortad((*bh)->b_data, alen, extoffset, inc)))
+				return -1;
+
+			etype = le32_to_cpu(sad->extLength) >> 30;
+			eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+			eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+			*elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+			break;
+		}
+		case ICB_FLAG_AD_LONG:
+		{
+			long_ad *lad;
+
+			if (!(lad = udf_get_filelongad((*bh)->b_data, alen, extoffset, inc)))
+				return -1;
+
+			etype = le32_to_cpu(lad->extLength) >> 30;
+			*eloc = lelb_to_cpu(lad->extLocation);
+			*elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+			break;
+		}
+		default:
+		{
+			udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+			return -1;
+		}
+	}
+	if (*elen)
+		return etype;
+
+	udf_debug("Empty Extent!\n");
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		*extoffset -= sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		*extoffset -= sizeof(long_ad);
+	return -1;
+}
+
+int udf_insert_aext(struct inode *inode, lb_addr bloc, int extoffset,
+    lb_addr neloc, Uint32 nelen, struct buffer_head *bh)
+{
+	lb_addr oeloc;
+	Uint32 oelen;
+	int type;
+
+	if (!bh)
+	{
+		if (!(bh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, bloc, 0),
+			inode->i_sb->s_blocksize)))
+		{
+			udf_debug("reading block %d failed!\n",
+				udf_get_lb_pblock(inode->i_sb, bloc, 0));
+			return -1;
+		}
+	}
+
+	while ((type = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
+	{
+		udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1);
+
+		neloc = oeloc;
+		nelen = (type << 30) | oelen;
+	}
+	udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
+	return (nelen >> 30);
+}
+
+int udf_delete_aext(struct inode *inode, lb_addr nbloc, int nextoffset,
+	lb_addr eloc, Uint32 elen, struct buffer_head *nbh)
+{
+	struct buffer_head *obh;
+	lb_addr obloc;
+	int oextoffset, adsize;
+	char type;
+	struct AllocExtDesc *aed;
+
+	if (!(nbh))
+	{
+		if (!(nbh = udf_tread(inode->i_sb,
+			udf_get_lb_pblock(inode->i_sb, nbloc, 0),
+			inode->i_sb->s_blocksize)))
+		{
+			udf_debug("reading block %d failed!\n",
+				udf_get_lb_pblock(inode->i_sb, nbloc, 0));
+			return -1;
+		}
+	}
+	else
+		atomic_inc(&nbh->b_count);
+	atomic_inc(&nbh->b_count);
+
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		adsize = 0;
+
+	obh = nbh;
+	obloc = nbloc;
+	oextoffset = nextoffset;
+
+	if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1)
+		return -1;
+
+	while ((type = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+	{
+		udf_write_aext(inode, obloc, &oextoffset, eloc, (type << 30) | elen, &obh, 1);
+		if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
+		{
+			obloc = nbloc;
+			udf_release_data(obh);
+			atomic_inc(&nbh->b_count);
+			obh = nbh;
+			oextoffset = nextoffset - adsize;
+		}
+	}
+	memset(&eloc, 0x00, sizeof(lb_addr));
+	elen = 0;
+
+	if (memcmp(&nbloc, &obloc, sizeof(lb_addr)))
+	{
+		udf_free_blocks(inode, nbloc, 0, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+		if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
+		{
+			UDF_I_LENALLOC(inode) -= (adsize * 2);
+			mark_inode_dirty(inode);
+		}
+		else
+		{
+			aed = (struct AllocExtDesc *)(obh)->b_data;
+			aed->lengthAllocDescs =
+				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
+			udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
+			mark_buffer_dirty(obh, 1);
+		}
+	}
+	else
+	{
+		udf_write_aext(inode, obloc, &oextoffset, eloc, elen, &obh, 1);
+		if (!memcmp(&UDF_I_LOCATION(inode), &obloc, sizeof(lb_addr)))
+		{
+			UDF_I_LENALLOC(inode) -= adsize;
+			mark_inode_dirty(inode);
+		}
+		else
+		{
+			aed = (struct AllocExtDesc *)(obh)->b_data;
+			aed->lengthAllocDescs =
+				cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
+			udf_update_tag((obh)->b_data, oextoffset - adsize);
+			mark_buffer_dirty(obh, 1);
+		}
+	}
+	
+	udf_release_data(nbh);
+	udf_release_data(obh);
+	return (elen >> 30);
+}
+
+int inode_bmap(struct inode *inode, int block, lb_addr *bloc, Uint32 *extoffset,
+	lb_addr *eloc, Uint32 *elen, Uint32 *offset, struct buffer_head **bh)
+{
+	int etype, lbcount = 0, b_off;
+
+	if (block < 0)
+	{
+		printk(KERN_ERR "udf: inode_bmap: block < 0\n");
+		return 0;
+	}
+	if (!inode)
+	{
+		printk(KERN_ERR "udf: inode_bmap: NULL inode\n");
+		return 0;
+	}
+
+	b_off = block << inode->i_sb->s_blocksize_bits;
+	*bloc = UDF_I_LOCATION(inode);
+	*eloc = UDF_I_EXT0LOC(inode);
+	*elen = UDF_I_EXT0LEN(inode) & UDF_EXTENT_LENGTH_MASK;
+	*extoffset = udf_file_entry_alloc_offset(inode);
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		*extoffset += sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		*extoffset += sizeof(long_ad);
+	etype = UDF_I_EXT0LEN(inode) >> 30;
+
+	while (lbcount + *elen <= b_off)
+	{
+		lbcount += *elen;
+		if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1)
+		{
+			*offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits;
+			return -1;
+		}
+	}
+	*offset = (b_off - lbcount) >> inode->i_sb->s_blocksize_bits;
+
+	return etype;
+}
+
+long udf_locked_block_map(struct inode *inode, long block)
+{
+	lb_addr eloc, bloc;
+	Uint32 offset, extoffset, elen;
+	struct buffer_head *bh = NULL;
+	int ret;
+
+	if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+		ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
+	else
+		ret = 0;
+
+	if (bh)
+		udf_release_data(bh);
+
+    if (UDF_SB(inode->i_sb)->s_flags & UDF_FLAG_VARCONV)
+		return udf_fixed_to_variable(ret);
+	else
+		return ret;
+}
+
+long udf_block_map(struct inode *inode, long block)
+{
+	int ret;
+
+	lock_kernel();
+	ret = udf_locked_block_map(inode, block);
+	unlock_kernel();
+	return ret;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/lowlevel.c linux/fs/udf/lowlevel.c
--- v2.3.16/linux/fs/udf/lowlevel.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/lowlevel.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,149 @@
+/*
+ * lowlevel.c
+ *
+ * PURPOSE
+ *  Low Level Device Routines for the UDF filesystem
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ *  03/26/99 blf  Created.
+ */
+
+#include "udfdecl.h"
+
+#include <linux/blkdev.h>
+#include <linux/cdrom.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+
+typedef struct scsi_device Scsi_Device;
+typedef struct scsi_cmnd   Scsi_Cmnd;
+
+#include <scsi/scsi_ioctl.h>
+
+#include <linux/udf_fs.h>
+#include "udf_sb.h"
+
+unsigned int 
+udf_get_last_session(kdev_t dev)
+{
+	struct cdrom_multisession ms_info;
+	unsigned int vol_desc_start;
+	struct inode inode_fake;
+	extern struct file_operations * get_blkfops(unsigned int);
+	int i;
+
+	vol_desc_start=0;
+	if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+	{
+		/* Whoops.  We must save the old FS, since otherwise
+		 * we would destroy the kernels idea about FS on root
+		 * mount in read_super... [chexum]
+		 */
+		mm_segment_t old_fs=get_fs();
+		inode_fake.i_rdev=dev;
+		ms_info.addr_format=CDROM_LBA;
+		set_fs(KERNEL_DS);
+		i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+						NULL,
+						CDROMMULTISESSION,
+						(unsigned long) &ms_info);
+		set_fs(old_fs);
+
+#define WE_OBEY_THE_WRITTEN_STANDARDS 1
+
+		if (i == 0)
+		{
+			udf_debug("XA disk: %s, vol_desc_start=%d\n",
+				(ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
+#if WE_OBEY_THE_WRITTEN_STANDARDS
+			if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+#endif
+				vol_desc_start = ms_info.addr.lba;
+		}
+		else
+		{
+			udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
+		}
+	}
+	else
+	{
+		udf_debug("Device doesn't know how to ioctl?\n");
+	}
+	return vol_desc_start;
+}
+
+unsigned int
+udf_get_last_block(kdev_t dev, int *flags)
+{
+	extern int *blksize_size[];
+	struct inode inode_fake;
+	extern struct file_operations * get_blkfops(unsigned int);
+	int ret;
+	unsigned long lblock;
+	unsigned int hbsize = get_hardblocksize(dev);
+	unsigned int mult = 0;
+	unsigned int div = 0;
+
+	if (!hbsize)
+		hbsize = 512;
+
+	if (hbsize > blksize_size[MAJOR(dev)][MINOR(dev)])
+		mult = hbsize / blksize_size[MAJOR(dev)][MINOR(dev)];
+	else if (blksize_size[MAJOR(dev)][MINOR(dev)] > hbsize)
+		div = blksize_size[MAJOR(dev)][MINOR(dev)] / hbsize;
+
+	if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+	{
+      /* Whoops.  We must save the old FS, since otherwise
+       * we would destroy the kernels idea about FS on root
+       * mount in read_super... [chexum]
+       */
+		mm_segment_t old_fs=get_fs();
+		inode_fake.i_rdev=dev;
+		set_fs(KERNEL_DS);
+
+		lblock = 0;
+		ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+			NULL,
+			BLKGETSIZE,
+			(unsigned long) &lblock);
+
+		if (!ret) /* Hard Disk */
+		{
+			if (mult)
+				lblock *= mult;
+			else if (div)
+				lblock /= div;
+		}
+		else /* CDROM */
+		{
+			ret = get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+				NULL,
+				CDROM_LAST_WRITTEN,
+				(unsigned long) &lblock);
+		}
+
+		set_fs(old_fs);
+		if (!ret)
+			return lblock - 1;
+	}
+	else
+	{
+		udf_debug("Device doesn't know how to ioctl?\n");
+	}
+	return 0;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/misc.c linux/fs/udf/misc.c
--- v2.3.16/linux/fs/udf/misc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/misc.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,540 @@
+/*
+ * misc.c
+ *
+ * PURPOSE
+ *	Miscellaneous routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998 Dave Boynton
+ *  (C) 1998-1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ *  04/19/99 blf  partial support for reading/writing specific EA's
+ */
+
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+#include "udfdecl.h"
+
+#include "udf_sb.h"
+#include "udf_i.h"
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/udf_fs.h>
+
+#else
+
+#include "udfdecl.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+int udf_blocksize=0;
+int udf_errno=0;
+
+void 
+udf_setblocksize(int size)
+{
+	udf_blocksize=size;
+}
+#endif
+
+Uint32
+udf64_low32(Uint64 indat)
+{
+	return indat & 0x00000000FFFFFFFFULL;
+}
+
+Uint32
+udf64_high32(Uint64 indat)
+{
+	return indat >> 32;
+}
+
+/*
+ * udf_stamp_to_time
+ */
+time_t * 
+udf_stamp_to_time(time_t *dest, timestamp src)
+{
+	struct ktm tm;
+
+	if ((!dest))
+		return NULL;
+
+	/* this is very rough. need to find source to mktime() */
+	tm.tm_year=(src.year) - 1900;	
+	tm.tm_mon=(src.month);
+	tm.tm_mday=(src.day);
+	tm.tm_hour=src.hour;
+	tm.tm_min=src.minute;
+	tm.tm_sec=src.second;
+	*dest = udf_converttime(&tm);
+	return dest;
+}
+
+uid_t udf_convert_uid(int uidin)
+{
+	if ( uidin == -1 )
+		return 0;
+	if ( uidin > (64*1024U - 1) ) /* 16 bit UID */
+		return 0;
+	return uidin;
+}
+
+gid_t udf_convert_gid(int gidin)
+{
+	if ( gidin == -1 )
+		return 0;
+	if ( gidin > (64*1024U - 1) ) /* 16 bit GID */
+		return 0;
+	return gidin;
+}
+
+#if defined(__linux__) && defined(__KERNEL__)
+
+extern struct buffer_head *
+udf_tread(struct super_block *sb, int block, int size)
+{
+	if (UDF_SB(sb)->s_flags & UDF_FLAG_VARCONV)
+		return bread(sb->s_dev, udf_fixed_to_variable(block), size);
+	else
+		return bread(sb->s_dev, block, size);
+}
+
+extern struct GenericAttrFormat *
+udf_add_extendedattr(struct inode * inode, Uint32 size, Uint32 type,
+	Uint8 loc, struct buffer_head **bh)
+{
+	Uint8 *ea = NULL, *ad = NULL;
+	long_ad eaicb;
+	int offset;
+
+	*bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+	if (UDF_I_EXTENDED_FE(inode) == 0)
+	{
+		struct FileEntry *fe;
+
+		fe = (struct FileEntry *)(*bh)->b_data;
+		eaicb = fe->extendedAttrICB;
+		offset = sizeof(struct FileEntry);
+	}
+	else
+	{
+		struct ExtendedFileEntry *efe;
+
+		efe = (struct ExtendedFileEntry *)(*bh)->b_data;
+		eaicb = efe->extendedAttrICB;
+		offset = sizeof(struct ExtendedFileEntry);
+	}
+
+	ea = &(*bh)->b_data[offset];
+	if (UDF_I_LENEATTR(inode))
+		offset += UDF_I_LENEATTR(inode);
+	else
+		size += sizeof(struct ExtendedAttrHeaderDesc);
+
+	ad = &(*bh)->b_data[offset];
+	if (UDF_I_LENALLOC(inode))
+		offset += UDF_I_LENALLOC(inode);
+
+	offset = inode->i_sb->s_blocksize - offset;
+
+	/* TODO - Check for FreeEASpace */
+
+	if (loc & 0x01 && offset >= size)
+	{
+		struct ExtendedAttrHeaderDesc *eahd;
+		eahd = (struct ExtendedAttrHeaderDesc *)ea;
+
+		if (UDF_I_LENALLOC(inode))
+		{
+			memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
+			UDF_I_EXT0OFFS(inode) += size;
+		}
+
+		if (UDF_I_LENEATTR(inode))
+		{
+			/* check checksum/crc */
+			if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
+				le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
+			{
+				udf_release_data(*bh);
+				return NULL;
+			}
+		}
+		else
+		{
+			size -= sizeof(struct ExtendedAttrHeaderDesc);
+			UDF_I_LENEATTR(inode) += sizeof(struct ExtendedAttrHeaderDesc);
+			eahd->descTag.tagIdent = cpu_to_le16(TID_EXTENDED_ATTRE_HEADER_DESC);
+			eahd->descTag.descVersion = cpu_to_le16(2);
+			eahd->descTag.tagSerialNum = cpu_to_le16(1);
+			eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+			eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
+			eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
+		}
+
+		offset = UDF_I_LENEATTR(inode);
+		if (type < 2048)
+		{
+			if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
+			{
+				Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
+				memmove(&ea[offset - aal + size],
+					&ea[aal], offset - aal);
+				offset -= aal;
+				eahd->appAttrLocation = cpu_to_le32(aal + size);
+			}
+			if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
+			{
+				Uint32 ial = le32_to_cpu(eahd->impAttrLocation);
+				memmove(&ea[offset - ial + size],
+					&ea[ial], offset - ial);
+				offset -= ial;
+				eahd->impAttrLocation = cpu_to_le32(ial + size);
+			}
+		}
+		else if (type < 65536)
+		{
+			if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
+			{
+				Uint32 aal = le32_to_cpu(eahd->appAttrLocation);
+				memmove(&ea[offset - aal + size],
+					&ea[aal], offset - aal);
+				offset -= aal;
+				eahd->appAttrLocation = cpu_to_le32(aal + size);
+			}
+		}
+		/* rewrite CRC + checksum of eahd */
+		UDF_I_LENEATTR(inode) += size;
+		return (struct GenericAttrFormat *)&ea[offset];
+	}
+	if (loc & 0x02)
+	{
+	}
+	udf_release_data(*bh);
+	return NULL;
+}
+
+extern struct GenericAttrFormat *
+udf_get_extendedattr(struct inode * inode, Uint32 type, Uint8 subtype,
+	struct buffer_head **bh)
+{
+	struct GenericAttrFormat *gaf;
+	Uint8 *ea = NULL;
+	long_ad eaicb;
+	Uint32 offset;
+
+	*bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+	if (UDF_I_EXTENDED_FE(inode) == 0)
+	{
+		struct FileEntry *fe;
+
+		fe = (struct FileEntry *)(*bh)->b_data;
+		eaicb = fe->extendedAttrICB;
+		if (UDF_I_LENEATTR(inode))
+			ea = fe->extendedAttr;
+	}
+	else
+	{
+		struct ExtendedFileEntry *efe;
+
+		efe = (struct ExtendedFileEntry *)(*bh)->b_data;
+		eaicb = efe->extendedAttrICB;
+		if (UDF_I_LENEATTR(inode))
+			ea = efe->extendedAttr;
+	}
+
+	if (UDF_I_LENEATTR(inode))
+	{
+		struct ExtendedAttrHeaderDesc *eahd;
+		eahd = (struct ExtendedAttrHeaderDesc *)ea;
+
+		/* check checksum/crc */
+		if (le16_to_cpu(eahd->descTag.tagIdent) != TID_EXTENDED_ATTRE_HEADER_DESC ||
+			le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
+		{
+			udf_release_data(*bh);
+			return NULL;
+		}
+	
+		if (type < 2048)
+			offset = sizeof(struct ExtendedAttrHeaderDesc);
+		else if (type < 65536)
+			offset = le32_to_cpu(eahd->impAttrLocation);
+		else
+			offset = le32_to_cpu(eahd->appAttrLocation);
+
+		while (offset < UDF_I_LENEATTR(inode))
+		{
+			gaf = (struct GenericAttrFormat *)&ea[offset];
+			if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
+				return gaf;
+			else
+				offset += le32_to_cpu(gaf->attrLength);
+		}
+	}
+
+	udf_release_data(*bh);
+	if (eaicb.extLength)
+	{
+		/* TODO */
+	}
+	return NULL;
+}
+
+extern struct buffer_head *
+udf_read_untagged(struct super_block *sb, Uint32 block, Uint32 offset)
+{
+	struct buffer_head *bh = NULL;
+
+	/* Read the block */
+	bh = udf_tread(sb, block+offset, sb->s_blocksize);
+	if (!bh)
+	{
+		printk(KERN_ERR "udf: udf_read_untagged(%p,%d,%d) failed\n",
+			sb, block, offset);
+		return NULL;
+	}
+	return bh;
+}
+
+/*
+ * udf_read_tagged
+ *
+ * PURPOSE
+ *	Read the first block of a tagged descriptor.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+extern struct buffer_head *
+udf_read_tagged(struct super_block *sb, Uint32 block, Uint32 location, Uint16 *ident)
+{
+	tag *tag_p;
+	struct buffer_head *bh = NULL;
+	register Uint8 checksum;
+	register int i;
+
+	/* Read the block */
+	if (block == 0xFFFFFFFF)
+		return NULL;
+
+	bh = udf_tread(sb, block, sb->s_blocksize);
+	if (!bh)
+	{
+		udf_debug("block=%d, location=%d: read failed\n", block, location);
+		return NULL;
+	}
+
+	tag_p = (tag *)(bh->b_data);
+
+	*ident = le16_to_cpu(tag_p->tagIdent);
+
+	if ( location != le32_to_cpu(tag_p->tagLocation) )
+	{
+		udf_debug("location mismatch block %d, tag %d != %d\n",
+			block, le32_to_cpu(tag_p->tagLocation), location);
+		goto error_out;
+	}
+	
+	/* Verify the tag checksum */
+	checksum = 0U;
+	for (i = 0; i < 4; i++)
+		checksum += (Uint8)(bh->b_data[i]);
+	for (i = 5; i < 16; i++)
+		checksum += (Uint8)(bh->b_data[i]);
+	if (checksum != tag_p->tagChecksum) {
+		printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
+		goto error_out;
+	}
+
+	/* Verify the tag version */
+	if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
+		le16_to_cpu(tag_p->descVersion) != 0x0003U)
+	{
+		udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
+			le16_to_cpu(tag_p->descVersion), block);
+		goto error_out;
+	}
+
+	/* Verify the descriptor CRC */
+	if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
+		le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
+			le16_to_cpu(tag_p->descCRCLength), 0))
+	{
+		return bh;
+	}
+	udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
+		block, le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
+
+error_out:
+	brelse(bh);
+	return NULL;
+}
+
+extern struct buffer_head *
+udf_read_ptagged(struct super_block *sb, lb_addr loc, Uint32 offset, Uint16 *ident)
+{
+	return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
+		loc.logicalBlockNum + offset, ident);
+}
+
+void udf_release_data(struct buffer_head *bh)
+{
+	if (bh)
+		brelse(bh);
+}
+
+#endif
+
+void udf_update_tag(char *data, int length)
+{
+	tag *tptr = (tag *)data;
+	int i;
+
+	length -= sizeof(tag);
+
+	tptr->tagChecksum = 0;
+	tptr->descCRCLength = le16_to_cpu(length);
+	tptr->descCRC = le16_to_cpu(udf_crc(data + sizeof(tag), length, 0));
+
+	for (i=0; i<16; i++)
+		if (i != 4)
+			tptr->tagChecksum += (Uint8)(data[i]);
+}
+
+void udf_new_tag(char *data, Uint16 ident, Uint16 version, Uint16 snum,
+	Uint32 loc, int length)
+{
+	tag *tptr = (tag *)data;
+	tptr->tagIdent = le16_to_cpu(ident);
+	tptr->descVersion = le16_to_cpu(version);
+	tptr->tagSerialNum = le16_to_cpu(snum);
+	tptr->tagLocation = le32_to_cpu(loc);
+	udf_update_tag(data, length);
+}
+
+#ifndef __KERNEL__
+/*
+ * udf_read_tagged_data
+ *
+ * PURPOSE
+ *	Read the first block of a tagged descriptor.
+ *	Usable from user-land.
+ *
+ * HISTORY
+ *	  10/4/98 dgb: written
+ */
+int
+udf_read_tagged_data(char *buffer, int size, int fd, int block, int offset)
+{
+	tag *tag_p;
+	register Uint8 checksum;
+	register int i;
+	unsigned long offs;
+
+	if (!buffer)
+	{
+		udf_errno = 1;
+		return -1;
+	}
+
+	if ( !udf_blocksize )
+	{
+		udf_errno = 2;
+		return -1;
+	}
+
+	if ( size < udf_blocksize )
+	{
+		udf_errno=3;
+		return -1;
+	}
+	udf_errno=0;
+	
+	offs=(long)block * udf_blocksize;
+	if ( lseek(fd, offs, SEEK_SET) != offs ) {
+		udf_errno=4;
+		return -1;
+	}
+
+	i=read(fd, buffer, udf_blocksize);
+	if ( i < udf_blocksize ) {
+		udf_errno=5;
+		return -1;
+	}
+
+	tag_p = (tag *)(buffer);
+
+	/* Verify the tag location */
+	if ((block-offset) != tag_p->tagLocation) {
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: location mismatch block %d, tag %d\n",
+			block, tag_p->tagLocation);
+#else
+		udf_errno=6;
+#endif
+		goto error_out;
+	}
+	
+	/* Verify the tag checksum */
+	checksum = 0U;
+	for (i = 0; i < 4; i++)
+		checksum += (Uint8)(buffer[i]);
+	for (i = 5; i < 16; i++)
+		checksum += (Uint8)(buffer[i]);
+	if (checksum != tag_p->tagChecksum) {
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: tag checksum failed\n");
+#else
+		udf_errno=7;
+#endif
+		goto error_out;
+	}
+
+	/* Verify the tag version */
+	if (tag_p->descVersion != 0x0002U) {
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: tag version 0x%04x != 0x0002U\n",
+			tag_p->descVersion);
+#else
+		udf_errno=8;
+#endif
+		goto error_out;
+	}
+
+	/* Verify the descriptor CRC */
+	if (tag_p->descCRC == udf_crc(buffer + 16, tag_p->descCRCLength, 0)) {
+		udf_errno=0;
+		return 0;
+	}
+#ifdef __KERNEL__
+	printk(KERN_ERR "udf: crc failure in udf_read_tagged\n");
+#else
+	udf_errno=9;
+#endif
+
+error_out:
+	return -1;
+}
+#endif
diff -u --recursive --new-file v2.3.16/linux/fs/udf/namei.c linux/fs/udf/namei.c
--- v2.3.16/linux/fs/udf/namei.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/namei.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,1302 @@
+/*
+ * namei.c
+ *
+ * PURPOSE
+ *      Inode name handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *      E-mail regarding any portion of the Linux UDF file system should be
+ *      directed to the development team mailing list (run by majordomo):
+ *              linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *      This file is distributed under the terms of the GNU General Public
+ *      License (GPL). Copies of the GPL can be obtained from:
+ *              ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *      Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998-1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ * 12/12/98 blf  Created. Split out the lookup code from dir.c
+ * 04/19/99 blf  link, mknod, symlink support
+ *
+ */
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/version.h>
+#include "udf_i.h"
+#include "udf_sb.h"
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/udf_fs.h>
+#endif
+
+#include "udfdecl.h"
+
+static inline int udf_match(int len, const char * const name, struct qstr *qs)
+{
+	if (len != qs->len)
+		return 0;
+	return !memcmp(name, qs->name, len);
+}
+
+int udf_write_fi(struct FileIdentDesc *cfi, struct FileIdentDesc *sfi,
+	struct udf_fileident_bh *fibh,
+	Uint8 *impuse, Uint8 *fileident)
+{
+	struct FileIdentDesc *efi;
+	Uint16 crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
+	Uint16 crc;
+	Uint8 checksum = 0;
+	int i;
+	int offset, len;
+	int padlen = fibh->eoffset - fibh->soffset - cfi->lengthOfImpUse - cfi->lengthFileIdent -
+		sizeof(struct FileIdentDesc);
+
+	crc = udf_crc((Uint8 *)cfi + sizeof(tag), sizeof(struct FileIdentDesc) -
+		sizeof(tag), 0);
+	efi = (struct FileIdentDesc *)(fibh->ebh->b_data + fibh->soffset);
+	if (fibh->sbh == fibh->ebh ||
+		(!fileident &&
+			(sizeof(struct FileIdentDesc) + (impuse ? cfi->lengthOfImpUse : 0))
+			<= -fibh->soffset))
+	{
+		memcpy((Uint8 *)sfi, (Uint8 *)cfi, sizeof(struct FileIdentDesc));
+
+		if (impuse)
+			memcpy(sfi->impUse, impuse, cfi->lengthOfImpUse);
+
+		if (fileident)
+			memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident,
+				cfi->lengthFileIdent);
+
+        /* Zero padding */
+		memset(sfi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0,
+			padlen);
+
+		if (fibh->sbh == fibh->ebh)
+			crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen, 0);
+		else
+		{
+			crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0);
+			crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+		}
+
+		sfi->descTag.descCRC = cpu_to_le32(crc);
+		sfi->descTag.descCRCLength = cpu_to_le16(crclen);
+
+		for (i=0; i<16; i++)
+			if (i != 4)
+				checksum += ((Uint8 *)&sfi->descTag)[i];
+
+		sfi->descTag.tagChecksum = checksum;
+
+		mark_buffer_dirty(fibh->sbh, 1);
+	}
+	else
+	{
+		offset = -fibh->soffset;
+		len = sizeof(struct FileIdentDesc);
+
+		if (len <= offset)
+			memcpy((Uint8 *)sfi, (Uint8 *)cfi, len);
+		else
+		{
+			memcpy((Uint8 *)sfi, (Uint8 *)cfi, offset);
+			memcpy(fibh->ebh->b_data, (Uint8 *)cfi + offset, len - offset);
+		}
+
+		offset -= len;
+		len = cfi->lengthOfImpUse;
+
+		if (impuse)
+		{
+			if (offset <= 0)
+				memcpy(efi->impUse, impuse, len);
+			else if (sizeof(struct FileIdentDesc) + len <= -fibh->soffset)
+				memcpy(sfi->impUse, impuse, len);
+			else
+			{
+				memcpy(sfi->impUse, impuse, offset);
+				memcpy(efi->impUse + offset, impuse + offset, len - offset);
+			}
+		}
+
+		offset -= len;
+		len = cfi->lengthFileIdent;
+
+		if (fileident)
+		{
+			if (offset <= 0)
+				memcpy(efi->fileIdent + cfi->lengthOfImpUse, fileident, len);
+			else
+			{
+				memcpy(sfi->fileIdent + cfi->lengthOfImpUse, fileident, offset);
+				memcpy(efi->fileIdent + cfi->lengthOfImpUse + offset,
+					fileident + offset, len - offset);
+			}
+		}
+
+        /* Zero padding */
+        memset(efi->fileIdent + cfi->lengthOfImpUse + cfi->lengthFileIdent, 0x00,
+			padlen);
+
+		if (sizeof(tag) < -fibh->soffset)
+		{
+			crc = udf_crc((Uint8 *)sfi + sizeof(tag), crclen - fibh->eoffset, 0);
+			crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+		}
+		else
+			crc = udf_crc((Uint8 *)fibh->ebh->b_data + fibh->eoffset - crclen, crclen, 0);
+
+		if (&(efi->descTag.descCRC) < (Uint16 *)fibh->ebh->b_data)
+		{
+			sfi->descTag.descCRC = cpu_to_le16(crc);
+			sfi->descTag.descCRCLength = cpu_to_le16(crclen);
+		}
+		else
+		{
+			efi->descTag.descCRC = cpu_to_le16(crc);
+			efi->descTag.descCRCLength = cpu_to_le16(crclen);
+		}
+
+		for (i=0; i<16; i++)
+		{
+			if (i != 4)
+			{
+				if (&(((Uint8 *)&efi->descTag)[i]) < (Uint8 *)fibh->ebh->b_data)
+					checksum += ((Uint8 *)&sfi->descTag)[i];
+				else
+					checksum += ((Uint8 *)&efi->descTag)[i];
+			}
+		}
+
+		if (&(cfi->descTag.tagChecksum) < (Uint8 *)fibh->ebh->b_data)
+			sfi->descTag.tagChecksum = checksum;
+		else
+			efi->descTag.tagChecksum = checksum;
+
+		mark_buffer_dirty(fibh->sbh, 1);
+		mark_buffer_dirty(fibh->ebh, 1);
+	}
+	return 0;
+}
+
+static struct FileIdentDesc *
+udf_find_entry(struct inode *dir, struct dentry *dentry,
+	struct udf_fileident_bh *fibh,
+	struct FileIdentDesc *cfi)
+{
+	struct FileIdentDesc *fi=NULL;
+	int f_pos, block;
+	int flen;
+	char fname[255];
+	char *nameptr;
+	Uint8 lfi;
+	Uint16 liu;
+	int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+	lb_addr bloc, eloc;
+	Uint32 extoffset, elen, offset;
+	struct buffer_head *bh = NULL;
+
+	if (!dir)
+		return NULL;
+
+	f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+	{
+		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+		if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+		{
+			if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+				extoffset -= sizeof(short_ad);
+			else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+				extoffset -= sizeof(long_ad);
+		}
+		else
+			offset = 0;
+	}
+	else
+	{
+		udf_release_data(bh);
+		return NULL;
+	}
+
+	if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+	{
+		udf_debug("udf_tread failed: block=%d\n", block);
+		udf_release_data(bh);
+		return NULL;
+	}
+
+	while ( (f_pos < size) )
+	{
+		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh);
+		liu = le16_to_cpu(cfi->lengthOfImpUse);
+		lfi = cfi->lengthFileIdent;
+
+		if (!fi)
+		{
+			if (fibh->sbh != fibh->ebh)
+				udf_release_data(fibh->ebh);
+			udf_release_data(fibh->sbh);
+			udf_release_data(bh);
+			return NULL;
+		}
+
+		if (fibh->sbh == fibh->ebh)
+		{
+			nameptr = fi->fileIdent + liu;
+		}
+		else
+		{
+			int poffset;	/* Unpaded ending offset */
+
+			poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi;
+
+			if (poffset >= lfi)
+				nameptr = (Uint8 *)(fibh->ebh->b_data + poffset - lfi);
+			else
+			{
+				nameptr = fname;
+				memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+				memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
+			}
+		}
+
+		if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 )
+		{
+			if ( !IS_UNDELETE(dir->i_sb) )
+				continue;
+		}
+	    
+		if ( (cfi->fileCharacteristics & FILE_HIDDEN) != 0 )
+		{
+			if ( !IS_UNHIDE(dir->i_sb) )
+				continue;
+		}
+
+		if (!lfi)
+			continue;
+
+		if ((flen = udf_get_filename(nameptr, fname, lfi)))
+		{
+			if (udf_match(flen, fname, &(dentry->d_name)))
+			{
+				udf_release_data(bh);
+				return fi;
+			}
+		}
+	}
+	if (fibh->sbh != fibh->ebh)
+		udf_release_data(fibh->ebh);
+	udf_release_data(fibh->sbh);
+	udf_release_data(bh);
+	return NULL;
+}
+
+/*
+ * udf_lookup
+ *
+ * PURPOSE
+ *	Look-up the inode for a given name.
+ *
+ * DESCRIPTION
+ *	Required - lookup_dentry() will return -ENOTDIR if this routine is not
+ *	available for a directory. The filesystem is useless if this routine is
+ *	not available for at least the filesystem's root directory.
+ *
+ *	This routine is passed an incomplete dentry - it must be completed by
+ *	calling d_add(dentry, inode). If the name does not exist, then the
+ *	specified inode must be set to null. An error should only be returned
+ *	when the lookup fails for a reason other than the name not existing.
+ *	Note that the directory inode semaphore is held during the call.
+ *
+ *	Refer to lookup_dentry() in fs/namei.c
+ *	lookup_dentry() -> lookup() -> real_lookup() -> .
+ *
+ * PRE-CONDITIONS
+ *	dir			Pointer to inode of parent directory.
+ *	dentry			Pointer to dentry to complete.
+ *
+ * POST-CONDITIONS
+ *	<return>		Zero on success.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+
+struct dentry *
+udf_lookup(struct inode *dir, struct dentry *dentry)
+{
+	struct inode *inode = NULL;
+	struct FileIdentDesc cfi, *fi;
+	struct udf_fileident_bh fibh;
+
+#ifdef UDF_RECOVERY
+	/* temporary shorthand for specifying files by inode number */
+	if (!strncmp(dentry->d_name.name, ".B=", 3) )
+	{
+		lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
+		inode = udf_iget(dir->i_sb, lb);
+		if (!inode)
+			return ERR_PTR(-EACCES);
+	}
+	else
+#endif /* UDF_RECOVERY */
+
+	if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
+	{
+		if (fibh.sbh != fibh.ebh)
+			udf_release_data(fibh.ebh);
+		udf_release_data(fibh.sbh);
+
+		inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
+		if ( !inode )
+			return ERR_PTR(-EACCES);
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+static struct FileIdentDesc *
+udf_add_entry(struct inode *dir, struct dentry *dentry,
+	struct udf_fileident_bh *fibh,
+	struct FileIdentDesc *cfi, int *err)
+{
+	struct super_block *sb;
+	struct FileIdentDesc *fi=NULL;
+	struct ustr unifilename;
+	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
+	int namelen;
+	int f_pos;
+	int flen;
+	char *nameptr;
+	int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+	int nfidlen;
+	Uint8 lfi;
+	Uint16 liu;
+	int block;
+	lb_addr bloc, eloc;
+	Uint32 extoffset, elen, offset;
+	struct buffer_head *bh = NULL;
+
+	*err = -EINVAL;
+	if (!dir || !dir->i_nlink)
+		return NULL;
+	sb = dir->i_sb;
+
+	if (!dentry->d_name.len)
+		return NULL;
+
+	if (dir->i_size == 0)
+	{
+		*err = -ENOENT;
+		return NULL;
+	}
+
+	if ( !(udf_char_to_ustr(&unifilename, dentry->d_name.name, dentry->d_name.len)) )
+	{
+		*err = -ENAMETOOLONG;
+		return NULL;
+	}
+
+	if ( !(namelen = udf_UTF8toCS0(name, &unifilename, UDF_NAME_LEN)) )
+		return 0;
+
+	nfidlen = (sizeof(struct FileIdentDesc) + 0 + namelen + 3) & ~3;
+
+	f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+	fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+	{
+		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+		if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+		{
+			if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+				extoffset -= sizeof(short_ad);
+			else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+				extoffset -= sizeof(long_ad);
+		}
+		else
+			offset = 0;
+	}
+	else
+	{
+		udf_release_data(bh);
+		return NULL;
+	}
+
+	if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		return NULL;
+
+	block = UDF_I_LOCATION(dir).logicalBlockNum;
+
+	while ( (f_pos < size) )
+	{
+		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &offset, &bh);
+		liu = le16_to_cpu(cfi->lengthOfImpUse);
+		lfi = cfi->lengthFileIdent;
+
+		if (!fi)
+		{
+			if (fibh->sbh != fibh->ebh)
+				udf_release_data(fibh->ebh);
+			udf_release_data(fibh->sbh);
+			udf_release_data(bh);
+			return NULL;
+		}
+
+		if (fibh->sbh == fibh->ebh)
+			nameptr = fi->fileIdent + liu;
+		else
+		{
+			int poffset;	/* Unpaded ending offset */
+
+			poffset = fibh->soffset + sizeof(struct FileIdentDesc) + liu + lfi;
+
+			if (poffset >= lfi)
+				nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
+			else
+			{
+				nameptr = fname;
+				memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
+				memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
+			}
+		}
+
+		if ( (cfi->fileCharacteristics & FILE_DELETED) != 0 )
+		{
+			if (((sizeof(struct FileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
+			{
+				udf_release_data(bh);
+				cfi->descTag.tagSerialNum = cpu_to_le16(1);
+				cfi->fileVersionNum = cpu_to_le16(1);
+				cfi->fileCharacteristics = 0;
+				cfi->lengthFileIdent = namelen;
+				cfi->lengthOfImpUse = cpu_to_le16(0);
+				if (!udf_write_fi(cfi, fi, fibh, NULL, name))
+					return fi;
+				else
+					return NULL;
+			}
+		}
+
+		if (!lfi)
+			continue;
+
+		if ((flen = udf_get_filename(nameptr, fname, lfi)))
+		{
+			if (udf_match(flen, fname, &(dentry->d_name)))
+			{
+				if (fibh->sbh != fibh->ebh)
+					udf_release_data(fibh->ebh);
+				udf_release_data(fibh->sbh);
+				udf_release_data(bh);
+				*err = -EEXIST;
+				return NULL;
+			}
+		}
+	}
+
+	f_pos += nfidlen;
+
+	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB &&
+		sb->s_blocksize - fibh->eoffset < nfidlen)
+	{
+		udf_release_data(bh);
+		bh = NULL;
+		fibh->soffset -= UDF_I_EXT0OFFS(dir);
+		fibh->eoffset -= UDF_I_EXT0OFFS(dir);
+		f_pos -= (UDF_I_EXT0OFFS(dir) >> 2);
+		udf_release_data(fibh->sbh);
+		if (!(fibh->sbh = fibh->ebh = udf_expand_adinicb(dir, &block, 1, err)))
+			return NULL;
+		bloc = UDF_I_LOCATION(dir);
+		extoffset = udf_file_entry_alloc_offset(dir);
+	}
+	else
+	{
+		if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+			extoffset -= sizeof(short_ad);
+		else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+			extoffset -= sizeof(long_ad);
+	}
+
+	dir->i_size += nfidlen;
+	if (sb->s_blocksize - fibh->eoffset >= nfidlen)
+	{
+		fibh->soffset = fibh->eoffset;
+		fibh->eoffset += nfidlen;
+		if (fibh->sbh != fibh->ebh)
+		{
+			udf_release_data(fibh->sbh);
+			fibh->sbh = fibh->ebh;
+		}
+
+		if (UDF_I_ALLOCTYPE(dir) != ICB_FLAG_AD_IN_ICB)
+		{
+			Uint32 lextoffset = extoffset;
+			if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) !=
+				EXTENT_RECORDED_ALLOCATED)
+			{
+				udf_release_data(bh);
+				udf_release_data(fibh->sbh);
+				return NULL;
+			}
+			else
+			{
+				elen += nfidlen;
+				elen = (EXTENT_RECORDED_ALLOCATED << 30) | elen;
+				udf_write_aext(dir, bloc, &lextoffset, eloc, elen, &bh, 1);
+				block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+			}
+		}
+		else
+			block = UDF_I_LOCATION(dir).logicalBlockNum;
+				
+		fi = (struct FileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
+	}
+	else
+	{
+		Uint32 lextoffset = extoffset;
+
+		fibh->soffset = fibh->eoffset - sb->s_blocksize;
+		fibh->eoffset += nfidlen - sb->s_blocksize;
+		if (fibh->sbh != fibh->ebh)
+		{
+			udf_release_data(fibh->sbh);
+			fibh->sbh = fibh->ebh;
+		}
+
+		if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) !=
+			EXTENT_RECORDED_ALLOCATED)
+		{
+			udf_release_data(bh);
+			udf_release_data(fibh->sbh);
+			return NULL;
+		}
+		else
+			block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+
+		*err = -ENOSPC;
+		if (!(fibh->ebh = udf_getblk(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
+		{
+			udf_release_data(bh);
+			udf_release_data(fibh->sbh);
+			return NULL;
+		}
+		if (!(fibh->soffset))
+		{
+			if (udf_next_aext(dir, &bloc, &lextoffset, &eloc, &elen, &bh, 1) ==
+				EXTENT_RECORDED_ALLOCATED)
+			{
+				block = eloc.logicalBlockNum + (elen >> dir->i_sb->s_blocksize_bits);
+			}
+			else
+				block ++;
+		}
+
+		fi = (struct FileIdentDesc *)(fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
+	}
+
+	memset(cfi, 0, sizeof(struct FileIdentDesc));
+	udf_new_tag((char *)cfi, TID_FILE_IDENT_DESC, 2, 1, block, sizeof(tag));
+	cfi->fileVersionNum = cpu_to_le16(1);
+	cfi->lengthFileIdent = namelen;
+	cfi->lengthOfImpUse = cpu_to_le16(0);
+	if (!udf_write_fi(cfi, fi, fibh, NULL, name))
+	{
+		udf_release_data(bh);
+		if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+			UDF_I_LENALLOC(dir) += nfidlen;
+		dir->i_version = ++event;
+		mark_inode_dirty(dir);
+		return fi;
+	}
+	else
+	{
+		udf_release_data(bh);
+		dir->i_size -= nfidlen;
+		if (fibh->sbh != fibh->ebh)
+			udf_release_data(fibh->ebh);
+		udf_release_data(fibh->sbh);
+		return NULL;
+	}
+}
+
+static int udf_delete_entry(struct FileIdentDesc *fi,
+	struct udf_fileident_bh *fibh,
+	struct FileIdentDesc *cfi)
+{
+	cfi->fileCharacteristics |= FILE_DELETED;
+	return udf_write_fi(cfi, fi, fibh, NULL, NULL);
+}
+
+int udf_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct udf_fileident_bh fibh;
+	struct inode *inode;
+	struct FileIdentDesc cfi, *fi;
+	int err;
+
+	inode = udf_new_inode(dir, mode, &err);
+	if (!inode)
+		return err;
+
+	inode->i_op = &udf_file_inode_operations;
+	inode->i_mode = mode;
+	mark_inode_dirty(inode);
+
+	if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+	{
+		udf_debug("udf_add_entry failure!\n");
+		inode->i_nlink --;
+		mark_inode_dirty(inode);
+		iput(inode);
+		return err;
+	}
+	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+	{
+		mark_inode_dirty(dir);
+		dir->i_version = ++event;
+	}
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	d_instantiate(dentry, inode);
+	return 0;
+}
+
+int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
+{
+	struct inode * inode;
+	struct udf_fileident_bh fibh;
+	int err;
+	struct FileIdentDesc cfi, *fi;
+
+	err = -EIO;
+	inode = udf_new_inode(dir, mode, &err);
+	if (!inode)
+		goto out;
+
+	inode->i_uid = current->fsuid;
+	inode->i_mode = mode;
+	inode->i_op = NULL;
+	if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+	{
+		udf_debug("udf_add_entry failure!\n");
+		inode->i_nlink --;
+		mark_inode_dirty(inode);
+		iput(inode);
+		return err;
+	}
+	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+	{
+		mark_inode_dirty(dir);
+		dir->i_version = ++event;
+	}
+	if (S_ISREG(inode->i_mode))
+	{
+		inode->i_op = &udf_file_inode_operations;
+	}
+	else if (S_ISCHR(inode->i_mode))
+	{
+		inode->i_op = &chrdev_inode_operations;
+	} 
+	else if (S_ISBLK(inode->i_mode))
+	{
+		inode->i_op = &blkdev_inode_operations;
+	}
+	else if (S_ISFIFO(inode->i_mode))
+	{
+		init_fifo(inode);
+	}
+	if (S_ISBLK(mode) || S_ISCHR(mode))
+		inode->i_rdev = to_kdev_t(rdev);
+	mark_inode_dirty(inode);
+
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	d_instantiate(dentry, inode);
+	err = 0;
+out:
+	return err;
+}
+
+int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	struct inode * inode;
+	struct udf_fileident_bh fibh;
+	int err;
+	struct FileEntry *fe;
+	struct FileIdentDesc cfi, *fi;
+	Uint32 loc;
+
+	err = -EMLINK;
+	if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
+		goto out;
+
+	err = -EIO;
+	inode = udf_new_inode(dir, S_IFDIR, &err);
+	if (!inode)
+		goto out;
+
+	inode->i_op = &udf_dir_inode_operations;
+	inode->i_size = (sizeof(struct FileIdentDesc) + 3) & ~3;
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		UDF_I_EXT0LEN(inode) = inode->i_size;
+		UDF_I_EXT0LOC(inode) = UDF_I_LOCATION(inode);
+		UDF_I_LENALLOC(inode) = inode->i_size;
+		loc = UDF_I_LOCATION(inode).logicalBlockNum;
+		fibh.sbh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+	}
+	else
+	{
+		fibh.sbh = udf_bread (inode, 0, 1, &err);
+		loc = UDF_I_EXT0LOC(inode).logicalBlockNum;
+	}
+
+	if (!fibh.sbh)
+	{
+		inode->i_nlink--;
+		mark_inode_dirty(inode);
+		iput(inode);
+		goto out;
+	}
+	inode->i_nlink = 2;
+	fe = (struct FileEntry *)fibh.sbh->b_data;
+	fi = (struct FileIdentDesc *)&(fe->extendedAttr[UDF_I_LENEATTR(inode)]);
+	udf_new_tag((char *)&cfi, TID_FILE_IDENT_DESC, 2, 1, loc,
+		sizeof(struct FileIdentDesc));
+	cfi.fileVersionNum = cpu_to_le16(1);
+	cfi.fileCharacteristics = FILE_DIRECTORY | FILE_PARENT;
+	cfi.lengthFileIdent = 0;
+	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir));
+	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
+	cfi.lengthOfImpUse = cpu_to_le16(0);
+	fibh.ebh = fibh.sbh;
+	fibh.soffset = sizeof(struct FileEntry);
+	fibh.eoffset = sizeof(struct FileEntry) + inode->i_size;
+	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	udf_release_data(fibh.sbh);
+	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+	if (dir->i_mode & S_ISGID)
+		inode->i_mode |= S_ISGID;
+	mark_inode_dirty(inode);
+
+	if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+	{
+		udf_debug("udf_add_entry failure!\n");
+		inode->i_nlink = 0;
+		mark_inode_dirty(inode);
+		iput(inode);
+		goto out;
+	}
+	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+	*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+		cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+	cfi.fileCharacteristics |= FILE_DIRECTORY;
+	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	dir->i_version = ++event;
+	dir->i_nlink++;
+	mark_inode_dirty(dir);
+	d_instantiate(dentry, inode);
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	err = 0;
+out:
+	return err;
+}
+
+static int empty_dir(struct inode *dir)
+{
+	struct FileIdentDesc *fi, cfi;
+	struct udf_fileident_bh fibh;
+	int f_pos;
+	int size = (UDF_I_EXT0OFFS(dir) + dir->i_size) >> 2;
+	int block;
+	lb_addr bloc, eloc;
+	Uint32 extoffset, elen, offset;
+	struct buffer_head *bh = NULL;
+
+	f_pos = (UDF_I_EXT0OFFS(dir) >> 2);
+
+	fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+	if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+		&bloc, &extoffset, &eloc, &elen, &offset, &bh) == EXTENT_RECORDED_ALLOCATED)
+	{
+		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
+		if (++offset < (elen >> dir->i_sb->s_blocksize_bits))
+		{
+			if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_SHORT)
+				extoffset -= sizeof(short_ad);
+			else if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_LONG)
+				extoffset -= sizeof(long_ad);
+		}
+		else
+			offset = 0;
+	}
+	else
+	{
+		udf_release_data(bh);
+		return 0;
+	}
+
+	if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block, dir->i_sb->s_blocksize)))
+		return 0;
+
+	while ( (f_pos < size) )
+	{
+		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &offset, &bh);
+
+		if (!fi)
+		{
+			if (fibh.sbh != fibh.ebh)
+				udf_release_data(fibh.ebh);
+			udf_release_data(fibh.sbh);
+			udf_release_data(bh);
+			return 0;
+		}
+
+		if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FILE_DELETED) == 0)
+		{
+			udf_release_data(bh);
+			return 0;
+		}
+	}
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	udf_release_data(bh);
+	return 1;
+}
+
+int udf_rmdir(struct inode * dir, struct dentry * dentry)
+{
+	int retval;
+	struct inode * inode;
+	struct udf_fileident_bh fibh;
+	struct FileIdentDesc *fi, cfi;
+
+	retval = -ENOENT;
+	fi = udf_find_entry(dir, dentry, &fibh, &cfi);
+	if (!fi)
+		goto out;
+
+	inode = dentry->d_inode;
+
+	retval = -EIO;
+	if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) != inode->i_ino)
+		goto end_rmdir;
+	retval = -ENOTEMPTY;
+	if (!empty_dir(inode))
+		goto end_rmdir;
+	retval = udf_delete_entry(fi, &fibh, &cfi);
+	dir->i_version = ++event;
+	if (retval)
+		goto end_rmdir;
+	if (inode->i_nlink != 2)
+		udf_warning(inode->i_sb, "udf_rmdir",
+			"empty directory has nlink != 2 (%d)",
+			inode->i_nlink);
+	inode->i_version = ++event;
+	inode->i_nlink = 0;
+	inode->i_size = 0;
+	mark_inode_dirty(inode);
+	dir->i_nlink --;
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	UDF_I_UCTIME(inode) = UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
+	mark_inode_dirty(dir);
+	d_delete(dentry);
+
+end_rmdir:
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+out:
+	return retval;
+}
+
+int udf_unlink(struct inode * dir, struct dentry * dentry)
+{
+	int retval;
+	struct inode * inode;
+	struct udf_fileident_bh fibh;
+	struct FileIdentDesc *fi;
+	struct FileIdentDesc cfi;
+
+	retval = -ENOENT;
+	fi = udf_find_entry(dir, dentry, &fibh, &cfi);
+	if (!fi)
+		goto out;
+
+	inode = dentry->d_inode;
+
+	retval = -EIO;
+
+	if (udf_get_lb_pblock(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation), 0) !=
+		inode->i_ino)
+	{
+		goto end_unlink;
+	}
+
+	if (!inode->i_nlink)
+	{
+		udf_debug("Deleting nonexistent file (%lu), %d\n",
+			inode->i_ino, inode->i_nlink);
+		inode->i_nlink = 1;
+	}
+	retval = udf_delete_entry(fi, &fibh, &cfi);
+	if (retval)
+		goto end_unlink;
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	UDF_I_UCTIME(dir) = UDF_I_UMTIME(dir) = CURRENT_UTIME;
+	mark_inode_dirty(dir);
+	inode->i_nlink--;
+	mark_inode_dirty(inode);
+	inode->i_ctime = dir->i_ctime;
+	retval = 0;
+	d_delete(dentry);	/* This also frees the inode */
+
+end_unlink:
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+out:
+	return retval;
+}
+
+int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
+{
+	struct inode * inode;
+	struct PathComponent *pc;
+	struct udf_fileident_bh fibh;
+	struct buffer_head *bh = NULL;
+	int eoffset, elen = 0;
+	struct FileIdentDesc *fi;
+	struct FileIdentDesc cfi;
+	char *ea;
+	int err;
+
+	if (!(inode = udf_new_inode(dir, S_IFLNK, &err)))
+		goto out;
+
+	inode->i_mode = S_IFLNK | S_IRWXUGO;
+	inode->i_op = &udf_symlink_inode_operations;
+
+	bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+	ea = bh->b_data + udf_file_entry_alloc_offset(inode);
+
+	eoffset = inode->i_sb->s_blocksize - (ea - bh->b_data);
+	pc = (struct PathComponent *)ea;
+
+	if (*symname == '/')
+	{
+		do
+		{
+			symname++;
+		} while (*symname == '/');
+
+		pc->componentType = 1;
+		pc->lengthComponentIdent = 0;
+		pc->componentFileVersionNum = 0;
+		pc += sizeof(struct PathComponent);
+		elen += sizeof(struct PathComponent);
+	}
+
+	while (*symname && eoffset > elen + sizeof(struct PathComponent))
+	{
+		char *compstart;
+		pc = (struct PathComponent *)(ea + elen);
+
+		compstart = (char *)symname;
+
+		do
+		{
+			symname++;
+		} while (*symname && *symname != '/');
+
+		pc->componentType = 5;
+		pc->lengthComponentIdent = 0;
+		pc->componentFileVersionNum = 0;
+		if (pc->componentIdent[0] == '.')
+		{
+			if (pc->lengthComponentIdent == 1)
+				pc->componentType = 4;
+			else if (pc->lengthComponentIdent == 2 && pc->componentIdent[1] == '.')
+				pc->componentType = 3;
+		}
+
+		if (pc->componentType == 5)
+		{
+			if (elen + sizeof(struct PathComponent) + symname - compstart > eoffset)
+				pc->lengthComponentIdent = eoffset - elen - sizeof(struct PathComponent);
+			else
+				pc->lengthComponentIdent = symname - compstart;
+
+			memcpy(pc->componentIdent, compstart, pc->lengthComponentIdent);
+		}
+
+		elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
+
+		if (*symname)
+		{
+			do
+			{
+				symname++;
+			} while (*symname == '/');
+		}
+	}
+
+	udf_release_data(bh);
+	UDF_I_LENALLOC(inode) = inode->i_size = elen;
+	mark_inode_dirty(inode);
+
+	if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+		goto out;
+	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+    if (UDF_SB_LVIDBH(inode->i_sb))
+    {
+        struct LogicalVolHeaderDesc *lvhd;
+        Uint64 uniqueID;
+        lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
+        uniqueID = le64_to_cpu(lvhd->uniqueID);
+		*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+			le32_to_cpu(uniqueID & 0x00000000FFFFFFFFUL);
+        if (!(++uniqueID & 0x00000000FFFFFFFFUL))
+            uniqueID += 16;
+        lvhd->uniqueID = cpu_to_le64(uniqueID);
+        mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1);
+	}
+	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+	{
+		mark_inode_dirty(dir);
+		dir->i_version = ++event;
+	}
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	d_instantiate(dentry, inode);
+	err = 0;
+
+out:
+	return err;
+}
+
+int udf_link(struct dentry * old_dentry, struct inode * dir,
+	 struct dentry *dentry)
+{
+	struct inode *inode = old_dentry->d_inode;
+	struct udf_fileident_bh fibh;
+	int err;
+	struct FileIdentDesc cfi, *fi;
+
+	if (S_ISDIR(inode->i_mode))
+		return -EPERM;
+
+	if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
+		return -EMLINK;
+
+	if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+		return err;
+	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
+	cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+    if (UDF_SB_LVIDBH(inode->i_sb))
+    {
+        struct LogicalVolHeaderDesc *lvhd;
+        Uint64 uniqueID;
+        lvhd = (struct LogicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
+        uniqueID = le64_to_cpu(lvhd->uniqueID);
+		*(Uint32 *)((struct ADImpUse *)cfi.icb.impUse)->impUse =
+			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
+        if (!(++uniqueID & 0x00000000FFFFFFFFUL))
+            uniqueID += 16;
+        lvhd->uniqueID = cpu_to_le64(uniqueID);
+        mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb), 1);
+	}
+	udf_write_fi(&cfi, fi, &fibh, NULL, NULL);
+	if (UDF_I_ALLOCTYPE(dir) == ICB_FLAG_AD_IN_ICB)
+	{
+		mark_inode_dirty(dir);
+		dir->i_version = ++event;
+	}
+	if (fibh.sbh != fibh.ebh)
+		udf_release_data(fibh.ebh);
+	udf_release_data(fibh.sbh);
+	inode->i_nlink ++;
+	inode->i_ctime = CURRENT_TIME;
+	UDF_I_UCTIME(inode) = CURRENT_UTIME;
+	mark_inode_dirty(inode);
+	inode->i_count ++;
+	d_instantiate(dentry, inode);
+	return 0;
+}
+
+/* Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
+	struct inode * new_dir, struct dentry * new_dentry)
+{
+	struct inode * old_inode, * new_inode;
+	struct udf_fileident_bh ofibh, nfibh;
+	struct FileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
+	struct buffer_head *dir_bh = NULL;
+	int retval = -ENOENT;
+
+	old_inode = old_dentry->d_inode;
+	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
+	if (!ofi || udf_get_lb_pblock(old_dir->i_sb, lelb_to_cpu(ocfi.icb.extLocation), 0) !=
+		old_inode->i_ino)
+	{
+		goto end_rename;
+	}
+
+	new_inode = new_dentry->d_inode;
+	nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
+	if (nfi)
+	{
+		if (!new_inode)
+		{
+			if (nfibh.sbh != nfibh.ebh)
+				udf_release_data(nfibh.ebh);
+			udf_release_data(nfibh.sbh);
+			nfi = NULL;
+		}
+		else
+		{
+/*
+			DQUOT_INIT(new_inode);
+*/
+		}
+	}
+	if (S_ISDIR(old_inode->i_mode))
+	{
+		Uint32 offset = UDF_I_EXT0OFFS(old_inode);
+
+		if (new_inode)
+		{
+			retval = -ENOTEMPTY;
+			if (!empty_dir(new_inode))
+				goto end_rename;
+		}
+		retval = -EIO;
+		dir_bh = udf_bread(old_inode, 0, 0, &retval);
+		if (!dir_bh)
+			goto end_rename;
+		dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset);
+		if (!dir_fi)
+			goto end_rename;
+		if (udf_get_lb_pblock(old_inode->i_sb, cpu_to_lelb(dir_fi->icb.extLocation), 0) !=
+			old_dir->i_ino)
+		{
+			goto end_rename;
+		}
+		retval = -EMLINK;
+		if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
+			goto end_rename;
+	}
+	if (!nfi)
+	{
+		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
+		if (!nfi)
+			goto end_rename;
+	}
+	new_dir->i_version = ++event;
+
+	/*
+	 * ok, that's it
+	 */
+	ncfi.fileVersionNum = ocfi.fileVersionNum;
+	ncfi.fileCharacteristics = ocfi.fileCharacteristics;
+	memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
+	udf_write_fi(&ncfi, nfi, &nfibh, NULL, NULL);
+
+	udf_delete_entry(ofi, &ofibh, &ocfi);
+
+	old_dir->i_version = ++event;
+	if (new_inode)
+	{
+		new_inode->i_nlink--;
+		new_inode->i_ctime = CURRENT_TIME;
+		UDF_I_UCTIME(new_inode) = CURRENT_UTIME;
+		mark_inode_dirty(new_inode);
+	}
+	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+	UDF_I_UCTIME(old_dir) = UDF_I_UMTIME(old_dir) = CURRENT_UTIME;
+	mark_inode_dirty(old_dir);
+
+	if (dir_bh)
+	{
+		dir_fi->icb.extLocation = lelb_to_cpu(UDF_I_LOCATION(new_dir));
+		udf_update_tag((char *)dir_fi, sizeof(struct FileIdentDesc) +
+			cpu_to_le16(dir_fi->lengthOfImpUse));
+		if (UDF_I_ALLOCTYPE(old_inode) == ICB_FLAG_AD_IN_ICB)
+		{
+			mark_inode_dirty(old_inode);
+			old_inode->i_version = ++event;
+		}
+		else
+			mark_buffer_dirty(dir_bh, 1);
+		old_dir->i_nlink --;
+		mark_inode_dirty(old_dir);
+		if (new_inode)
+		{
+			new_inode->i_nlink --;
+			mark_inode_dirty(new_inode);
+		}
+		else
+		{
+			new_dir->i_nlink ++;
+			mark_inode_dirty(new_dir);
+		}
+	}
+
+	retval = 0;
+
+end_rename:
+	udf_release_data(dir_bh);
+	if (ofi)
+	{
+		if (ofibh.sbh != ofibh.ebh)
+			udf_release_data(ofibh.ebh);
+		udf_release_data(ofibh.sbh);
+	}
+	if (nfi)
+	{
+		if (nfibh.sbh != nfibh.ebh)
+			udf_release_data(nfibh.ebh);
+		udf_release_data(nfibh.sbh);
+	}
+	return retval;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/partition.c linux/fs/udf/partition.c
--- v2.3.16/linux/fs/udf/partition.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/partition.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,190 @@
+/*
+ * partition.c
+ *
+ * PURPOSE
+ *      Partition handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *      E-mail regarding any portion of the Linux UDF file system should be
+ *      directed to the development team mailing list (run by majordomo):
+ *              linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *      This file is distributed under the terms of the GNU General Public
+ *      License (GPL). Copies of the GPL can be obtained from:
+ *              ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *      Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ * 12/06/98 blf  Created file. 
+ *
+ */
+
+#include "udfdecl.h"
+#include "udf_sb.h"
+#include "udf_i.h"
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/udf_fs.h>
+
+extern Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+	Uint16 ident;
+
+	if (partition >= UDF_SB_NUMPARTS(sb))
+	{
+		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
+			block, partition, offset);
+		return 0xFFFFFFFF;
+	}
+	switch (UDF_SB_PARTTYPE(sb, partition))
+	{
+		case UDF_TYPE1_MAP15:
+		{
+			return UDF_SB_PARTROOT(sb, partition) + block + offset;
+		}
+		case UDF_VIRTUAL_MAP15:
+		case UDF_VIRTUAL_MAP20:
+		{
+			struct buffer_head *bh = NULL;
+			Uint32 newblock;
+			Uint32 index;
+			Uint32 loc;
+
+			index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32);
+
+
+			if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
+			{
+				udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
+					block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+				return 0xFFFFFFFF;
+			}
+
+			if (block >= index)
+			{
+				block -= index;
+				newblock = 1 + (block / (sb->s_blocksize / sizeof(Uint32)));
+				index = block % (sb->s_blocksize / sizeof(Uint32));
+			}
+			else
+			{
+				newblock = 0;
+				index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block;
+			}
+
+			loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock);
+
+			if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
+			{
+				udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
+					sb, block, partition, loc, index);
+				return 0xFFFFFFFF;
+			}
+
+			loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
+
+			udf_release_data(bh);
+
+			if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
+			{
+				udf_debug("recursive call to udf_get_pblock!\n");
+				return 0xFFFFFFFF;
+			}
+
+			return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+		}
+		case UDF_SPARABLE_MAP15:
+		{
+			Uint32 newblock = UDF_SB_PARTROOT(sb, partition) + block + offset;
+			Uint32 spartable = UDF_SB_TYPESPAR(sb, partition).s_spar_loc;
+			Uint32 plength = UDF_SB_TYPESPAR(sb,partition).s_spar_plen;
+			Uint32 packet = (block + offset) & (~(plength-1));
+			struct buffer_head *bh = NULL;
+			struct SparingTable *st;
+			SparingEntry *se;
+
+			bh = udf_read_tagged(sb, spartable, spartable, &ident);
+
+			if (!bh)
+			{
+				printk(KERN_ERR "udf: udf_read_tagged(%p,%d,%d)\n",
+					sb, spartable, spartable);
+				return 0xFFFFFFFF;
+			}
+
+			st = (struct SparingTable *)bh->b_data;
+			if (ident == 0)
+			{
+				if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
+				{
+					Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
+					Uint16 index;
+
+					/* If the sparing table span multiple blocks, find out which block we are on */
+
+					se = &(st->mapEntry[0]);
+
+					if (rtl * sizeof(SparingEntry) + sizeof(struct SparingTable) > sb->s_blocksize)
+					{
+						index = (sb->s_blocksize - sizeof(struct SparingTable)) / sizeof(SparingEntry);
+						if (le32_to_cpu(se[index-1].origLocation) == packet)
+						{
+							udf_release_data(bh);
+							return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+						}
+						else if (le32_to_cpu(se[index-1].origLocation) < packet)
+						{
+							do
+							{
+								udf_release_data(bh);
+								bh = udf_tread(sb, spartable, sb->s_blocksize);
+								if (!bh)
+									return 0xFFFFFFFF;
+								se = (SparingEntry *)bh->b_data;
+								spartable ++;
+								rtl -= index;
+								index = sb->s_blocksize / sizeof(SparingEntry);
+
+								if (le32_to_cpu(se[index].origLocation) == packet)
+								{
+									udf_release_data(bh);
+									return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+								}
+							} while (rtl * sizeof(SparingEntry) > sb->s_blocksize && 
+								le32_to_cpu(se[index-1].origLocation) < packet);
+						}
+					}
+			
+					for (index=0; index<rtl; index++)
+					{
+						if (le32_to_cpu(se[index].origLocation) == packet)
+						{
+							udf_release_data(bh);
+							return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+						}
+						else if (le32_to_cpu(se[index].origLocation) > packet)
+						{
+							udf_release_data(bh);
+							return newblock;
+						}
+					}
+
+					udf_release_data(bh);
+					return newblock;
+				}
+			}
+			udf_release_data(bh);
+		}
+	}
+	return 0xFFFFFFFF;
+}
+
+extern Uint32 udf_get_lb_pblock(struct super_block *sb, lb_addr loc, Uint32 offset)
+{
+	return udf_get_pblock(sb, loc.logicalBlockNum, loc.partitionReferenceNum, offset);
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/super.c linux/fs/udf/super.c
--- v2.3.16/linux/fs/udf/super.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/super.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,1623 @@
+/*
+ * super.c
+ *
+ * PURPOSE
+ *  Super block routines for the OSTA-UDF(tm) filesystem.
+ *
+ * DESCRIPTION
+ *  OSTA-UDF(tm) = Optical Storage Technology Association
+ *  Universal Disk Format.
+ *
+ *  This code is based on version 2.00 of the UDF specification,
+ *  and revision 3 of the ECMA 167 standard [equivalent to ISO 13346].
+ *    http://www.osta.org/
+ *    http://www.ecma.ch/
+ *    http://www.iso.org/
+ *
+ * CONTACTS
+ *  E-mail regarding any portion of the Linux UDF file system should be
+ *  directed to the development team mailing list (run by majordomo):
+ *	  linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *  This file is distributed under the terms of the GNU General Public
+ *  License (GPL). Copies of the GPL can be obtained from:
+ *    ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *  Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998 Dave Boynton
+ *  (C) 1998-1999 Ben Fennema
+ *
+ * HISTORY
+ *
+ *  09/24/98 dgb  changed to allow compiling outside of kernel, and
+ *                added some debugging.
+ *  10/01/98 dgb  updated to allow (some) possibility of compiling w/2.0.34
+ *  10/16/98      attempting some multi-session support
+ *  10/17/98      added freespace count for "df"
+ *  11/11/98 gr   added novrs option
+ *  11/26/98 dgb  added fileset,anchor mount options
+ *  12/06/98 blf  really hosed things royally. vat/sparing support. sequenced vol descs
+ *                rewrote option handling based on isofs
+ *  12/20/98      find the free space bitmap (if it exists)
+ */
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#include "udfdecl.h"    
+
+#include <linux/blkdev.h>
+#include <linux/malloc.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/cdrom.h>
+#include <linux/nls.h>
+#include <asm/byteorder.h>
+
+#include <linux/udf_fs.h>
+#include "udf_sb.h"
+#include "udf_i.h"
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+static char error_buf[1024];
+
+/* These are the "meat" - everything else is stuffing */
+static struct super_block *udf_read_super(struct super_block *, void *, int);
+static void udf_put_super(struct super_block *);
+static int udf_remount_fs(struct super_block *, int *, char *);
+static int udf_check_valid(struct super_block *, int, int);
+static int udf_vrs(struct super_block *sb, int silent);
+static int udf_load_partition(struct super_block *, lb_addr *);
+static int udf_load_logicalvol(struct super_block *, struct buffer_head *, lb_addr *);
+static void udf_load_logicalvolint(struct super_block *, extent_ad);
+static int udf_find_anchor(struct super_block *, int, int);
+static int udf_find_fileset(struct super_block *, lb_addr *, lb_addr *);
+static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
+static void udf_load_fileset(struct super_block *, struct buffer_head *, lb_addr *);
+static void udf_load_partdesc(struct super_block *, struct buffer_head *);
+static void udf_open_lvid(struct super_block *);
+static void udf_close_lvid(struct super_block *);
+static unsigned int udf_count_free(struct super_block *);
+
+/* version specific functions */
+static int udf_statfs(struct super_block *, struct statfs *, int);
+
+/* UDF filesystem type */
+static struct file_system_type udf_fstype = {
+	"udf",			/* name */
+	FS_REQUIRES_DEV,	/* fs_flags */
+	udf_read_super,		/* read_super */
+	NULL			/* next */
+};
+
+/* Superblock operations */
+static struct super_operations udf_sb_ops =
+{
+	udf_read_inode,		/* read_inode */
+#ifdef CONFIG_UDF_RW
+	udf_write_inode,	/* write_inode */
+#else
+	NULL,				/* write_inode */
+#endif
+	udf_put_inode,		/* put_inode */
+#ifdef CONFIG_UDF_RW
+	udf_delete_inode,	/* delete_inode */
+#else
+	NULL,				/* delete_inode */
+#endif
+	NULL,				/* notify_change */
+	udf_put_super,		/* put_super */
+	NULL,				/* write_super */
+	udf_statfs,			/* statfs */
+	udf_remount_fs,		/* remount_fs */
+	NULL,				/* clear_inode */
+	NULL,				/* umount_begin */
+};
+
+struct udf_options
+{
+	unsigned char novrs;
+	unsigned char utf8;
+	unsigned int blocksize;
+	unsigned int session;
+	unsigned int lastblock;
+	unsigned int anchor;
+	unsigned int volume;
+	unsigned short partition;
+	unsigned int fileset;
+	unsigned int rootdir;
+	unsigned int flags;
+	mode_t umask;
+	gid_t gid;
+	uid_t uid;
+	char *iocharset;
+};
+
+#if defined(MODULE)
+	
+/*
+ * cleanup_module
+ *
+ * PURPOSE
+ *	Unregister the UDF filesystem type.
+ *
+ * DESCRIPTION
+ *	Clean-up before the module is unloaded.
+ *	This routine only applies when compiled as a module.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+int
+cleanup_module(void)
+{
+	printk(KERN_NOTICE "udf: unregistering filesystem\n");
+	return unregister_filesystem(&udf_fstype);
+}
+
+/*
+ * init_module / init_udf_fs
+ *
+ * PURPOSE
+ *	Register the UDF filesystem type.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+int init_module(void)
+#else /* if !defined(MODULE) */
+int __init init_udf_fs(void)
+#endif
+{
+	printk(KERN_NOTICE "udf: registering filesystem\n");
+	{
+		struct super_block sb;
+		int size;
+
+		size = sizeof(struct super_block) +
+			(int)&sb.u - (int)&sb;
+		if ( size < sizeof(struct udf_sb_info) )
+		{
+			printk(KERN_ERR "udf: Danger! Kernel was compiled without enough room for udf_sb_info\n");
+			printk(KERN_ERR "udf: Kernel has room for %u bytes, udf needs %u\n",
+				size, sizeof(struct udf_sb_info));
+			return 0;
+		}
+	}
+	return register_filesystem(&udf_fstype);
+}
+
+/*
+ * udf_parse_options
+ *
+ * PURPOSE
+ *	Parse mount options.
+ *
+ * DESCRIPTION
+ *	The following mount options are supported:
+ *
+ *	gid=		Set the default group.
+ *	umask=		Set the default umask.
+ *	uid=		Set the default user.
+ *	unhide		Show otherwise hidden files.
+ *	undelete	Show deleted files in lists.
+ *	strict		Set strict conformance (unused)
+ *	utf8		(unused)
+ *	iocharset	(unused)
+ *
+ *	The remaining are for debugging and disaster recovery:
+ *
+ *	bs=		Set the block size. (may not work unless 2048)
+ *	novrs           Skip volume sequence recognition 
+ *
+ *	The following expect a offset from 0.
+ *
+ *	session=	Set the CDROM session (default= last session)
+ *	anchor=		Override standard anchor location. (default= 256)
+ *	volume=		Override the VolumeDesc location. (unused)
+ *	partition=	Override the PartitionDesc location. (unused)
+ *	lastblock=	Set the last block of the filesystem/
+ *
+ *	The following expect a offset from the partition root.
+ *
+ *	fileset=	Override the fileset block location. (unused)
+ *	rootdir=	Override the root directory location. (unused)
+ *		WARNING: overriding the rootdir to a non-directory may
+ *		yield highly unpredictable results.
+ *
+ * PRE-CONDITIONS
+ *	options		Pointer to mount options string.
+ *	uopts		Pointer to mount options variable.
+ *
+ * POST-CONDITIONS
+ *	<return>	0	Mount options parsed okay.
+ *	<return>	-1	Error parsing mount options.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+
+static int
+udf_parse_options(char *options, struct udf_options *uopt)
+{
+	char *opt, *val;
+
+	uopt->novrs = 0;
+	uopt->blocksize = 2048;
+	uopt->partition = 0xFFFF;
+	uopt->session = 0xFFFFFFFF;
+	uopt->lastblock = 0xFFFFFFFF;
+	uopt->anchor = 0xFFFFFFFF;
+	uopt->volume = 0xFFFFFFFF;
+	uopt->rootdir = 0xFFFFFFFF;
+	uopt->fileset = 0xFFFFFFFF;
+	uopt->iocharset = NULL;
+
+	if (!options)
+		return 1;
+
+        for (opt = strtok(options, ","); opt; opt = strtok(NULL, ","))
+	{
+		/* Make "opt=val" into two strings */
+		val = strchr(opt, '=');
+		if (val)
+			*(val++) = 0;
+		if (!strcmp(opt, "novrs") && !val)
+			uopt->novrs = 1;
+		else if (!strcmp(opt, "utf8") && !val)
+			uopt->utf8 = 1;
+		else if (!strcmp(opt, "bs") && val)
+			uopt->blocksize = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "unhide") && !val)
+			uopt->flags |= UDF_FLAG_UNHIDE;
+		else if (!strcmp(opt, "undelete") && !val)
+			uopt->flags |= UDF_FLAG_UNDELETE;
+		else if (!strcmp(opt, "gid") && val)
+			uopt->gid = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "umask") && val)
+			uopt->umask = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "strict") && !val)
+			uopt->flags |= UDF_FLAG_STRICT;
+		else if (!strcmp(opt, "uid") && val)
+			uopt->uid = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "session") && val)
+			uopt->session = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "lastblock") && val)
+			uopt->lastblock = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "anchor") && val)
+			uopt->anchor = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "volume") && val)
+			uopt->volume = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "partition") && val)
+			uopt->partition = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "fileset") && val)
+			uopt->fileset = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "rootdir") && val)
+			uopt->rootdir = simple_strtoul(val, NULL, 0);
+		else if (!strcmp(opt, "iocharset") && val)
+		{
+			uopt->iocharset = val;
+			while (*val && *val != ',')
+				val ++;
+			if (val == uopt->iocharset)
+				return 0;
+			*val = 0;
+		}
+		else if (val)
+		{
+			printk(KERN_ERR "udf: bad mount option \"%s=%s\"\n",
+				opt, val);
+			return 0;
+		}
+		else
+		{
+			printk(KERN_ERR "udf: bad mount option \"%s\"\n",
+				opt);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int
+udf_remount_fs(struct super_block *sb, int *flags, char *options)
+{
+	struct udf_options uopt;
+
+	uopt.flags =    UDF_SB(sb)->s_flags ;
+	uopt.uid =      UDF_SB(sb)->s_uid ;
+	uopt.gid =      UDF_SB(sb)->s_gid ;
+	uopt.umask =    UDF_SB(sb)->s_umask ;
+	uopt.utf8 =     UDF_SB(sb)->s_utf8 ;
+
+	if ( !udf_parse_options(options, &uopt) )
+		return -EINVAL;
+
+	UDF_SB(sb)->s_flags =   uopt.flags;
+	UDF_SB(sb)->s_uid =     uopt.uid;
+	UDF_SB(sb)->s_gid =     uopt.gid;
+	UDF_SB(sb)->s_umask =   uopt.umask;
+	UDF_SB(sb)->s_utf8 =    uopt.utf8;
+
+	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+		return 0;
+	if (*flags & MS_RDONLY)
+		udf_close_lvid(sb);
+	else
+		udf_open_lvid(sb);
+
+	return 0;
+}
+
+/*
+ * udf_set_blocksize
+ *
+ * PURPOSE
+ *	Set the block size to be used in all transfers.
+ *
+ * DESCRIPTION
+ *	To allow room for a DMA transfer, it is best to guess big when unsure.
+ *	This routine picks 2048 bytes as the blocksize when guessing. This
+ *	should be adequate until devices with larger block sizes become common.
+ *
+ *	Note that the Linux kernel can currently only deal with blocksizes of
+ *	512, 1024, 2048, 4096, and 8192 bytes.
+ *
+ * PRE-CONDITIONS
+ *	sb			Pointer to _locked_ superblock.
+ *
+ * POST-CONDITIONS
+ *	sb->s_blocksize		Blocksize.
+ *	sb->s_blocksize_bits	log2 of blocksize.
+ *	<return>	0	Blocksize is valid.
+ *	<return>	1	Blocksize is invalid.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static  int
+udf_set_blocksize(struct super_block *sb, int bsize)
+{
+	/* Use specified block size if specified */
+	sb->s_blocksize = get_hardblocksize(sb->s_dev);
+	sb->s_blocksize = sb->s_blocksize ? sb->s_blocksize : 2048;
+	if (bsize > sb->s_blocksize)
+		sb->s_blocksize = bsize;
+
+	/* Block size must be an even multiple of 512 */
+	switch (sb->s_blocksize) {
+		case 512: sb->s_blocksize_bits = 9;	break;
+		case 1024: sb->s_blocksize_bits = 10; break;
+		case 2048: sb->s_blocksize_bits = 11; break;
+		case 4096: sb->s_blocksize_bits = 12; break;
+		case 8192: sb->s_blocksize_bits = 13; break;
+		default:
+		{
+			udf_debug("Bad block size (%ld)\n", sb->s_blocksize);
+			printk(KERN_ERR "udf: bad block size (%ld)\n", sb->s_blocksize);
+			return 0;
+		}
+	}
+
+	/* Set the block size */
+	set_blocksize(sb->s_dev, sb->s_blocksize);
+	return sb->s_blocksize;
+}
+
+static int
+udf_vrs(struct super_block *sb, int silent)
+{
+	struct VolStructDesc *vsd = NULL;
+	int sector = 32768;
+	struct buffer_head *bh = NULL;
+	int iso9660=0;
+	int nsr02=0;
+	int nsr03=0;
+
+	/* Block size must be a multiple of 512 */
+	if (sb->s_blocksize & 511)
+		return sector;
+
+	sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits);
+
+	udf_debug("Starting at sector %u (%ld byte sectors)\n",
+		(sector >> sb->s_blocksize_bits), sb->s_blocksize);
+	/* Process the sequence (if applicable) */
+	for (;!nsr02 && !nsr03; sector += 2048)
+	{
+		/* Read a block */
+		bh = udf_tread(sb, sector >> sb->s_blocksize_bits, 2048);
+		if (!bh)
+			break;
+
+		/* Look for ISO  descriptors */
+		vsd = (struct VolStructDesc *)(bh->b_data +
+			(sector & (sb->s_blocksize - 1)));
+
+		if (vsd->stdIdent[0] == 0)
+		{
+			udf_release_data(bh);
+			break;
+		}
+		else if (!strncmp(vsd->stdIdent, STD_ID_CD001, STD_ID_LEN))
+		{
+			iso9660 = sector;
+			switch (vsd->structType)
+			{
+				case 0: 
+					udf_debug("ISO9660 Boot Record found\n");
+					break;
+				case 1: 
+					udf_debug("ISO9660 Primary Volume Descriptor found\n");
+					break;
+				case 2: 
+					udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
+					break;
+				case 3: 
+					udf_debug("ISO9660 Volume Partition Descriptor found\n");
+					break;
+				case 255: 
+					udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
+					break;
+				default: 
+					udf_debug("ISO9660 VRS (%u) found\n", vsd->structType);
+					break;
+			}
+		}
+		else if (!strncmp(vsd->stdIdent, STD_ID_BEA01, STD_ID_LEN))
+		{
+		}
+		else if (!strncmp(vsd->stdIdent, STD_ID_TEA01, STD_ID_LEN))
+		{
+			udf_release_data(bh);
+			break;
+		}
+		else if (!strncmp(vsd->stdIdent, STD_ID_NSR02, STD_ID_LEN))
+		{
+			nsr02 = sector;
+		}
+		else if (!strncmp(vsd->stdIdent, STD_ID_NSR03, STD_ID_LEN))
+		{
+			nsr03 = sector;
+		}
+		udf_release_data(bh);
+	}
+
+	if (nsr03)
+		return nsr03;
+	else if (nsr02)
+		return nsr02;
+	else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768)
+		return -1;
+	else
+		return 0;
+}
+
+/*
+ * udf_find_anchor
+ *
+ * PURPOSE
+ *	Find an anchor volume descriptor.
+ *
+ * PRE-CONDITIONS
+ *	sb			Pointer to _locked_ superblock.
+ *	lastblock		Last block on media.
+ *
+ * POST-CONDITIONS
+ *	<return>		1 if not found, 0 if ok
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static int
+udf_find_anchor(struct super_block *sb, int useranchor, int lastblock)
+{
+	int varlastblock = udf_variable_to_fixed(lastblock);
+	int last[] =  { lastblock, lastblock - 2,
+					lastblock - 150, lastblock - 152,
+					varlastblock, varlastblock - 2,
+					varlastblock - 150, varlastblock - 152 };
+	struct buffer_head *bh = NULL;
+	Uint16 ident;
+	Uint32 location;
+	int i;
+
+	UDF_SB_ANCHOR(sb)[0] = 0;
+	UDF_SB_ANCHOR(sb)[1] = 0;
+	UDF_SB_ANCHOR(sb)[2] = 0;
+	UDF_SB_ANCHOR(sb)[3] = 256 + UDF_SB_SESSION(sb);
+
+	lastblock = 0;
+
+	/* Search for an anchor volume descriptor pointer */
+
+	/*  according to spec, anchor is in either:
+	 *     block 256
+	 *     lastblock-256
+	 *     lastblock
+	 *  however, if the disc isn't closed, it could be 512 */
+
+	for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
+	{
+		if (!(bh = bread(sb->s_dev, last[i], sb->s_blocksize)))
+		{
+			ident = location = 0;
+		}
+		else
+		{
+			ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+			location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+			udf_release_data(bh);
+		}
+
+		if (ident == TID_ANCHOR_VOL_DESC_PTR)
+		{
+			if (location == last[i] - UDF_SB_SESSION(sb))
+			{
+				lastblock = UDF_SB_ANCHOR(sb)[0] = last[i];
+				UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+			}
+			else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
+			{
+				UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV;
+				lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]);
+				UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+			}
+			else
+				udf_debug("Anchor found at block %d, location mismatch %d.\n",
+					last[i], location);
+		}
+		else if (ident == TID_FILE_ENTRY || ident == TID_EXTENDED_FILE_ENTRY)
+		{
+			lastblock = last[i];
+			UDF_SB_ANCHOR(sb)[2] = 512 + UDF_SB_SESSION(sb);
+		}
+		else
+		{
+			if (!(bh = bread(sb->s_dev, last[i] - 256, sb->s_blocksize)))
+			{
+				ident = location = 0;
+			}
+			else
+			{
+				ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+				location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+				udf_release_data(bh);
+			}
+
+			if (ident == TID_ANCHOR_VOL_DESC_PTR &&
+				location == last[i] - 256 - UDF_SB_SESSION(sb))
+			{
+				lastblock = last[i];
+				UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
+			}
+			else
+			{
+				if (!(bh = bread(sb->s_dev, last[i] - 312 - UDF_SB_SESSION(sb),
+					sb->s_blocksize)))
+				{
+					ident = location = 0;
+				}
+				else
+				{
+					ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+					location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+					udf_release_data(bh);
+				}
+
+				if (ident == TID_ANCHOR_VOL_DESC_PTR &&
+					location == udf_variable_to_fixed(last[i]) - 256)
+				{
+					UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV;
+					lastblock = udf_variable_to_fixed(last[i]);
+					UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
+				}
+			}
+		}
+	}
+
+	if (!lastblock)
+	{
+		/* We havn't found the lastblock. check 312 */
+		if ((bh = bread(sb->s_dev, 312 + UDF_SB_SESSION(sb), sb->s_blocksize)))
+		{
+			ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
+			location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
+			udf_release_data(bh);
+
+			if (ident == TID_ANCHOR_VOL_DESC_PTR && location == 256)
+				UDF_SB(sb)->s_flags |= UDF_FLAG_VARCONV;
+		}
+	}
+
+	for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
+	{
+		if (UDF_SB_ANCHOR(sb)[i])
+		{
+			if (!(bh = udf_read_tagged(sb,
+				UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
+			{
+				UDF_SB_ANCHOR(sb)[i] = 0;
+			}
+			else
+			{
+				udf_release_data(bh);
+				if ((ident != TID_ANCHOR_VOL_DESC_PTR) && (i ||
+					(ident != TID_FILE_ENTRY && ident != TID_EXTENDED_FILE_ENTRY)))
+				{
+					UDF_SB_ANCHOR(sb)[i] = 0;
+				}
+			}
+		}
+		else if (useranchor != 0xFFFFFFFF)
+		{
+			UDF_SB_ANCHOR(sb)[i] = useranchor;
+			useranchor = 0xFFFFFFFF;
+			i --;
+		}
+	}
+
+	return lastblock;
+}
+
+static int 
+udf_find_fileset(struct super_block *sb, lb_addr *fileset, lb_addr *root)
+{
+	struct buffer_head *bh = NULL;
+	long lastblock;
+	Uint16 ident;
+
+	if (fileset->logicalBlockNum != 0xFFFFFFFF ||
+		fileset->partitionReferenceNum != 0xFFFF)
+	{
+		bh = udf_read_ptagged(sb, *fileset, 0, &ident);
+
+		if (!bh)
+			return 1;
+		else if (ident != TID_FILE_SET_DESC)
+		{
+			udf_release_data(bh);
+			return 1;
+		}
+			
+	}
+
+	if (!bh) /* Search backwards through the partitions */
+	{
+		lb_addr newfileset;
+
+		return 1;
+		
+		for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1;
+			(newfileset.partitionReferenceNum != 0xFFFF &&
+				fileset->logicalBlockNum == 0xFFFFFFFF &&
+				fileset->partitionReferenceNum == 0xFFFF);
+			newfileset.partitionReferenceNum--)
+		{
+			lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum);
+			newfileset.logicalBlockNum = 0;
+
+			do
+			{
+				bh = udf_read_ptagged(sb, newfileset, 0, &ident);
+				if (!bh)
+				{
+					newfileset.logicalBlockNum ++;
+					continue;
+				}
+
+				switch (ident)
+				{
+					case TID_SPACE_BITMAP_DESC:
+					{
+						struct SpaceBitmapDesc *sp;
+						sp = (struct SpaceBitmapDesc *)bh->b_data;
+						newfileset.logicalBlockNum += 1 +
+							((le32_to_cpu(sp->numOfBytes) + sizeof(struct SpaceBitmapDesc) - 1)
+								>> sb->s_blocksize_bits);
+						udf_release_data(bh);
+						break;
+					}
+					case TID_FILE_SET_DESC:
+					{
+						*fileset = newfileset;
+						break;
+					}
+					default:
+					{
+						newfileset.logicalBlockNum ++;
+						udf_release_data(bh);
+						bh = NULL;
+						break;
+					}
+				}
+			}
+			while (newfileset.logicalBlockNum < lastblock &&
+				fileset->logicalBlockNum == 0xFFFFFFFF &&
+				fileset->partitionReferenceNum == 0xFFFF);
+		}
+	}
+
+	if ((fileset->logicalBlockNum != 0xFFFFFFFF ||
+		fileset->partitionReferenceNum != 0xFFFF) && bh)
+	{
+		udf_debug("Fileset at block=%d, partition=%d\n",
+			fileset->logicalBlockNum, fileset->partitionReferenceNum);
+
+		UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
+		udf_load_fileset(sb, bh, root);
+		udf_release_data(bh);
+		return 0;
+	}
+	return 1;
+}
+
+static void 
+udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
+{
+	struct PrimaryVolDesc *pvoldesc;
+	time_t recording;
+	struct ustr instr;
+	struct ustr outstr;
+
+	pvoldesc = (struct PrimaryVolDesc *)bh->b_data;
+
+	if ( udf_stamp_to_time(&recording, lets_to_cpu(pvoldesc->recordingDateAndTime)) )
+	{
+	    timestamp ts;
+	    ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
+		udf_debug("recording time %ld, %u/%u/%u %u:%u (%x)\n",
+			recording, ts.year, ts.month, ts.day, ts.hour, ts.minute,
+			ts.typeAndTimezone);
+	    UDF_SB_RECORDTIME(sb) = recording;
+	}
+
+	if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) )
+	{
+		if (!udf_CS0toUTF8(&outstr, &instr))
+		{
+			udf_debug("volIdent[] = '%s'\n", outstr.u_name);
+			strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name, outstr.u_len);
+		}
+	}
+
+	if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) )
+	{
+		if (!udf_CS0toUTF8(&outstr, &instr))
+			udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
+	}
+}
+
+static void 
+udf_load_fileset(struct super_block *sb, struct buffer_head *bh, lb_addr *root)
+{
+	struct FileSetDesc *fset;
+
+	fset = (struct FileSetDesc *)bh->b_data;
+
+	*root = lelb_to_cpu(fset->rootDirectoryICB.extLocation);
+
+	UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum);
+
+	udf_debug("Rootdir at block=%d, partition=%d\n", 
+		root->logicalBlockNum, root->partitionReferenceNum);
+}
+
+static void 
+udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
+{
+	struct PartitionDesc *p;
+	int i;
+
+	p=(struct PartitionDesc *)bh->b_data;
+
+	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
+	{
+		udf_debug("Searching map: (%d == %d)\n", 
+			UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
+		if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber))
+		{
+			UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
+			UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation) + UDF_SB_SESSION(sb);
+			UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
+
+			if (!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR02) ||
+				!strcmp(p->partitionContents.ident, PARTITION_CONTENTS_NSR03))
+			{
+				struct PartitionHeaderDesc *phd;
+
+				phd = (struct PartitionHeaderDesc *)(p->partitionContentsUse);
+				if (phd->unallocatedSpaceTable.extLength)
+					udf_debug("unallocatedSpaceTable (part %d)\n", i);
+				if (phd->unallocatedSpaceBitmap.extLength)
+				{
+					UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap =
+						le32_to_cpu(phd->unallocatedSpaceBitmap.extPosition);
+					udf_debug("unallocatedSpaceBitmap (part %d) @ %d\n",
+						i, UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap);
+				}
+				if (phd->partitionIntegrityTable.extLength)
+					udf_debug("partitionIntegrityTable (part %d)\n", i);
+				if (phd->freedSpaceTable.extLength)
+					udf_debug("freedSpaceTable (part %d)\n", i);
+				if (phd->freedSpaceBitmap.extLength)
+					udf_debug("freedSpaceBitmap (part %d\n", i);
+			}
+			break;
+		}
+	}
+	if (i == UDF_SB_NUMPARTS(sb))
+	{
+		udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber));
+	}
+	else
+	{
+		udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
+			le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
+			UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
+	}
+}
+
+static int 
+udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, lb_addr *fileset)
+{
+	struct LogicalVolDesc *lvd;
+	int i, offset;
+	Uint8 type;
+
+	lvd = (struct LogicalVolDesc *)bh->b_data;
+
+	UDF_SB_NUMPARTS(sb) = le32_to_cpu(lvd->numPartitionMaps);
+	UDF_SB_ALLOC_PARTMAPS(sb, UDF_SB_NUMPARTS(sb));
+
+	for (i=0,offset=0;
+		 i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength);
+		 i++,offset+=((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength)
+	{
+		type = ((struct GenericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
+		udf_debug("Partition (%d) type %d\n", i, type);
+		if (type == 1)
+		{
+			struct GenericPartitionMap1 *gpm1 = (struct GenericPartitionMap1 *)&(lvd->partitionMaps[offset]);
+			UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15;
+			UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum);
+			UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum);
+		}
+		else if (type == 2)
+		{
+			struct UdfPartitionMap2 *upm2 = (struct UdfPartitionMap2 *)&(lvd->partitionMaps[offset]);
+			if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL)))
+			{
+				if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0150)
+					UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15;
+				else if (le16_to_cpu(((Uint16 *)upm2->partIdent.identSuffix)[0]) == 0x0200)
+					UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
+			}
+			else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
+			{
+				struct SparablePartitionMap *spm = (struct SparablePartitionMap *)&(lvd->partitionMaps[offset]);
+				UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
+				UDF_SB_TYPESPAR(sb,i).s_spar_plen = le16_to_cpu(spm->packetLength);
+				UDF_SB_TYPESPAR(sb,i).s_spar_loc = le32_to_cpu(spm->locSparingTable[0]);
+			}
+			else
+			{
+				udf_debug("Unknown ident: %s\n", upm2->partIdent.ident);
+				continue;
+			}
+			UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum);
+			UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
+		}
+	}
+
+	if (fileset)
+	{
+		long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
+
+		*fileset = lelb_to_cpu(la->extLocation);
+		udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
+			fileset->logicalBlockNum,
+			fileset->partitionReferenceNum);
+	}
+	if (lvd->integritySeqExt.extLength)
+		udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
+	return 0;
+}
+
+/*
+ * udf_load_logicalvolint
+ *
+ */
+static void
+udf_load_logicalvolint(struct super_block *sb, extent_ad loc)
+{
+	struct buffer_head *bh = NULL;
+	Uint16 ident;
+
+	while ((bh = udf_read_tagged(sb, loc.extLocation, loc.extLocation, &ident)) &&
+		ident == TID_LOGICAL_VOL_INTEGRITY_DESC && loc.extLength > 0)
+	{
+		UDF_SB_LVIDBH(sb) = bh;
+		
+		if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength)
+			udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
+		
+		if (UDF_SB_LVIDBH(sb) != bh)
+			udf_release_data(bh);
+		loc.extLength -= sb->s_blocksize;
+		loc.extLocation ++;
+	}
+	if (UDF_SB_LVIDBH(sb) != bh)
+		udf_release_data(bh);
+}
+
+/*
+ * udf_process_sequence
+ *
+ * PURPOSE
+ *	Process a main/reserve volume descriptor sequence.
+ *
+ * PRE-CONDITIONS
+ *	sb			Pointer to _locked_ superblock.
+ *	block			First block of first extent of the sequence.
+ *	lastblock		Lastblock of first extent of the sequence.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static  int
+udf_process_sequence(struct super_block *sb, long block, long lastblock, lb_addr *fileset)
+{
+	struct buffer_head *bh = NULL;
+	struct udf_vds_record vds[VDS_POS_LENGTH];
+	struct GenericDesc *gd;
+	int done=0;
+	int i,j;
+	Uint32 vdsn;
+	Uint16 ident;
+
+	memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
+
+	/* Read the main descriptor sequence */
+	for (;(!done && block <= lastblock); block++)
+	{
+
+		bh = udf_read_tagged(sb, block, block, &ident);
+		if (!bh) 
+			break;
+
+		/* Process each descriptor (ISO 13346 3/8.3-8.4) */
+		gd = (struct GenericDesc *)bh->b_data;
+		vdsn = le32_to_cpu(gd->volDescSeqNum);
+		switch (ident)
+		{
+			case TID_PRIMARY_VOL_DESC: /* ISO 13346 3/10.1 */
+				if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum)
+				{
+					vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
+					vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
+				}
+				break;
+			case TID_VOL_DESC_PTR: /* ISO 13346 3/10.3 */
+				if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum)
+				{
+					vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
+					vds[VDS_POS_VOL_DESC_PTR].block = block;
+				}
+				break;
+			case TID_IMP_USE_VOL_DESC: /* ISO 13346 3/10.4 */
+				if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum)
+				{
+					vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
+					vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
+				}
+				break;
+			case TID_PARTITION_DESC: /* ISO 13346 3/10.5 */
+				if (!vds[VDS_POS_PARTITION_DESC].block)
+					vds[VDS_POS_PARTITION_DESC].block = block;
+				break;
+			case TID_LOGICAL_VOL_DESC: /* ISO 13346 3/10.6 */
+				if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum)
+				{
+					vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
+					vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
+				}
+				break;
+			case TID_UNALLOC_SPACE_DESC: /* ISO 13346 3/10.8 */
+				if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum)
+				{
+					vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
+					vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
+				}
+				break;
+			case TID_TERMINATING_DESC: /* ISO 13346 3/10.9 */
+				vds[VDS_POS_TERMINATING_DESC].block = block;
+				done = 1;
+				break;
+		}
+		udf_release_data(bh);
+	}
+	for (i=0; i<VDS_POS_LENGTH; i++)
+	{
+		if (vds[i].block)
+		{
+			bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident);
+
+			if (i == VDS_POS_PRIMARY_VOL_DESC)
+				udf_load_pvoldesc(sb, bh);
+			else if (i == VDS_POS_LOGICAL_VOL_DESC)
+				udf_load_logicalvol(sb, bh, fileset);
+			else if (i == VDS_POS_PARTITION_DESC)
+			{
+				struct buffer_head *bh2 = NULL;
+				udf_load_partdesc(sb, bh);
+				for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
+				{
+					bh2 = udf_read_tagged(sb, j, j, &ident);
+					gd = (struct GenericDesc *)bh2->b_data;
+					if (ident == TID_PARTITION_DESC)
+						udf_load_partdesc(sb, bh2);
+					udf_release_data(bh2);
+				}
+			}
+			udf_release_data(bh);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * udf_check_valid()
+ */
+static int
+udf_check_valid(struct super_block *sb, int novrs, int silent)
+{
+	long block;
+
+	if (novrs)
+	{
+		udf_debug("Validity check skipped because of novrs option\n");
+		return 0;
+	}
+	/* Check that it is NSR02 compliant */
+	/* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
+	else if ((block = udf_vrs(sb, silent)) == -1)
+	{
+		udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+		return 0;
+	}
+	else 
+		return !block;
+}
+
+static int
+udf_load_partition(struct super_block *sb, lb_addr *fileset)
+{
+	struct AnchorVolDescPtr *anchor;
+	Uint16 ident;
+	struct buffer_head *bh;
+	long main_s, main_e, reserve_s, reserve_e;
+	int i;
+
+	if (!sb)
+	    return 1;
+
+	for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
+	{
+		if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
+			UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i] - UDF_SB_SESSION(sb), &ident)))
+		{
+			anchor = (struct AnchorVolDescPtr *)bh->b_data;
+
+			/* Locate the main sequence */
+			main_s = le32_to_cpu( anchor->mainVolDescSeqExt.extLocation );
+			main_e = le32_to_cpu( anchor->mainVolDescSeqExt.extLength );
+			main_e = main_e >> sb->s_blocksize_bits;
+			main_e += main_s;
+	
+			/* Locate the reserve sequence */
+			reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
+			reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
+			reserve_e = reserve_e >> sb->s_blocksize_bits;
+			reserve_e += reserve_s;
+
+			udf_release_data(bh);
+
+			/* Process the main & reserve sequences */
+			/* responsible for finding the PartitionDesc(s) */
+			if (!(udf_process_sequence(sb, main_s, main_e, fileset) &&
+				udf_process_sequence(sb, reserve_s, reserve_e, fileset)))
+			{
+				break;
+			}
+		}
+	}
+
+	if (i == sizeof(UDF_SB_ANCHOR(sb))/sizeof(int))
+	{
+		udf_debug("No Anchor block found\n");
+		return 1;
+	}
+	else
+		udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]);
+
+	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
+	{
+		switch UDF_SB_PARTTYPE(sb, i)
+		{
+			case UDF_VIRTUAL_MAP15:
+			case UDF_VIRTUAL_MAP20:
+			{
+				lb_addr ino;
+
+				if (!UDF_SB_LASTBLOCK(sb))
+				{
+					udf_debug("Unable to determine Lastblock (For Virtual Partition)\n");
+					return 1;
+				}
+
+				if (i == 0)
+					ino.partitionReferenceNum = i+1;
+				else
+					ino.partitionReferenceNum = i-1;
+
+				ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) - UDF_SB_PARTROOT(sb,ino.partitionReferenceNum);
+
+				if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
+					return 1;
+
+				if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15)
+				{
+					UDF_SB_TYPEVIRT(sb,i).s_start_offset = UDF_I_EXT0OFFS(UDF_SB_VAT(sb));
+					UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) / sizeof(Uint32);
+				}
+				else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
+				{
+					struct buffer_head *bh = NULL;
+					Uint32 pos;
+
+					pos = udf_block_map(UDF_SB_VAT(sb), 0);
+					bh = bread(sb->s_dev, pos, sb->s_blocksize);
+					UDF_SB_TYPEVIRT(sb,i).s_start_offset =
+						le16_to_cpu(((struct VirtualAllocationTable20 *)bh->b_data + UDF_I_EXT0OFFS(UDF_SB_VAT(sb)))->lengthHeader) +
+							UDF_I_EXT0OFFS(UDF_SB_VAT(sb));
+					UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
+						UDF_SB_TYPEVIRT(sb,i).s_start_offset) / sizeof(Uint32);
+					udf_release_data(bh);
+				}
+				UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
+				UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
+				UDF_SB_PARTMAPS(sb)[i].s_uspace_bitmap = 0xFFFFFFFF;
+			}
+		}
+	}
+	return 0;
+}
+
+static void udf_open_lvid(struct super_block *sb)
+{
+#ifdef CONFIG_UDF_RW
+	if (UDF_SB_LVIDBH(sb))
+	{
+		int i;
+		timestamp cpu_time;
+
+		UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+		UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+		if (udf_time_to_stamp(&cpu_time, CURRENT_TIME, CURRENT_UTIME))
+			UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+		UDF_SB_LVID(sb)->integrityType = INTEGRITY_TYPE_OPEN;
+
+		UDF_SB_LVID(sb)->descTag.descCRC =
+			cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+			le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+
+		UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
+		for (i=0; i<16; i++)
+			if (i != 4)
+				UDF_SB_LVID(sb)->descTag.tagChecksum +=
+					((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
+
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	}
+#endif
+}
+
+static void udf_close_lvid(struct super_block *sb)
+{
+#ifdef CONFIG_UDF_RW
+	if (UDF_SB_LVIDBH(sb) &&
+		UDF_SB_LVID(sb)->integrityType == INTEGRITY_TYPE_OPEN)
+	{
+		int i;
+		timestamp cpu_time;
+
+		UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+		UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+		if (udf_time_to_stamp(&cpu_time, CURRENT_TIME, CURRENT_UTIME))
+			UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+		
+		UDF_SB_LVID(sb)->integrityType = INTEGRITY_TYPE_CLOSE;
+
+		UDF_SB_LVID(sb)->descTag.descCRC =
+			cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+			le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+
+		UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
+		for (i=0; i<16; i++)
+			if (i != 4)
+				UDF_SB_LVID(sb)->descTag.tagChecksum +=
+					((Uint8 *)&(UDF_SB_LVID(sb)->descTag))[i];
+
+		mark_buffer_dirty(UDF_SB_LVIDBH(sb), 1);
+	}
+#endif
+}
+
+/*
+ * udf_read_super
+ *
+ * PURPOSE
+ *	Complete the specified super block.
+ *
+ * PRE-CONDITIONS
+ *	sb			Pointer to superblock to complete - never NULL.
+ *	sb->s_dev		Device to read suberblock from.
+ *	options			Pointer to mount options.
+ *	silent			Silent flag.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static struct super_block *
+udf_read_super(struct super_block *sb, void *options, int silent)
+{
+	struct inode *inode=NULL;
+	struct udf_options uopt;
+	lb_addr rootdir, fileset;
+	int i;
+
+	uopt.flags = 0;
+	uopt.uid = 0;
+	uopt.gid = 0;
+	uopt.umask = 0;
+	uopt.utf8 = 0;
+
+	/* Lock the module in memory (if applicable) */
+	MOD_INC_USE_COUNT;
+
+	lock_super(sb);
+
+	UDF_SB_PARTMAPS(sb) = NULL;
+	UDF_SB_LVIDBH(sb) = NULL;
+	UDF_SB_VAT(sb) = NULL;
+
+	if (!udf_parse_options((char *)options, &uopt))
+		goto error_out;
+
+	memset(UDF_SB_ANCHOR(sb), 0x00, sizeof(UDF_SB_ANCHOR(sb)));
+	fileset.logicalBlockNum = 0xFFFFFFFF;
+	fileset.partitionReferenceNum = 0xFFFF;
+	UDF_SB_RECORDTIME(sb)=0;
+	UDF_SB_VOLIDENT(sb)[0]=0;
+
+	UDF_SB(sb)->s_flags = uopt.flags;
+	UDF_SB(sb)->s_uid = uopt.uid;
+	UDF_SB(sb)->s_gid = uopt.gid;
+	UDF_SB(sb)->s_umask = uopt.umask;
+	UDF_SB(sb)->s_utf8 = uopt.utf8;
+
+	/* Set the block size for all transfers */
+	if (!udf_set_blocksize(sb, uopt.blocksize))
+		goto error_out;
+
+	if ( uopt.session == 0xFFFFFFFF )
+		UDF_SB_SESSION(sb) = udf_get_last_session(sb->s_dev);
+	else
+		UDF_SB_SESSION(sb) = uopt.session;
+
+	udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb));
+
+	if ( uopt.lastblock == 0xFFFFFFFF )
+		UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb->s_dev, &(UDF_SB(sb)->s_flags));
+	else
+		UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
+
+	UDF_SB_LASTBLOCK(sb) = udf_find_anchor(sb, uopt.anchor, UDF_SB_LASTBLOCK(sb));
+
+	udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
+
+	if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */
+	{
+		udf_debug("No VRS found\n");
+ 		goto error_out;
+	}
+
+	UDF_SB_CHARSET(sb) = NULL;
+
+#ifdef CONFIG_NLS
+	if (uopt.utf8 == 0)
+	{
+		char *p = uopt.iocharset ? uopt.iocharset : "iso8859-1";
+		UDF_SB_CHARSET(sb) = load_nls(p);
+		if (!UDF_SB_CHARSET(sb))
+			if (uopt.iocharset)
+				goto error_out;
+		UDF_SB_CHARSET(sb) = load_nls_default();
+	}
+#endif
+
+	/* Fill in the rest of the superblock */
+	sb->s_op = &udf_sb_ops;
+	sb->s_time = 0;
+	sb->dq_op = NULL;
+	sb->s_dirt = 0;
+	sb->s_magic = UDF_SUPER_MAGIC;
+
+	for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
+	{
+		UDF_SB_BLOCK_BITMAP_NUMBER(sb,i) = 0;
+		UDF_SB_BLOCK_BITMAP(sb,i) = NULL;
+	}
+	UDF_SB_LOADED_BLOCK_BITMAPS(sb) = 0;
+
+	if (udf_load_partition(sb, &fileset))
+	{
+		udf_debug("No partition found (1)\n");
+		goto error_out;
+	}
+
+	if ( !UDF_SB_NUMPARTS(sb) )
+	{
+		udf_debug("No partition found (2)\n");
+		goto error_out;
+	}
+
+	if ( udf_find_fileset(sb, &fileset, &rootdir) )
+	{
+		udf_debug("No fileset found\n");
+		goto error_out;
+	}
+
+	if (!silent)
+	{
+		timestamp ts;
+		udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb), 0);
+		udf_info("Mounting volume '%s', timestamp %u/%02u/%u %02u:%02u\n",
+			UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute);
+	}
+	if (!(sb->s_flags & MS_RDONLY))
+		udf_open_lvid(sb);
+	unlock_super(sb);
+
+	/* Assign the root inode */
+	/* assign inodes by physical block number */
+	/* perhaps it's not extensible enough, but for now ... */
+	inode = udf_iget(sb, rootdir); 
+	if (!inode)
+	{
+		udf_debug("Error in udf_iget, block=%d, partition=%d\n",
+			rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+		goto error_out;
+	}
+
+	/* Allocate a dentry for the root inode */
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root)
+	{
+		iput(inode);
+		udf_debug("Couldn't allocate root dentry\n");
+		goto error_out;
+	}
+
+	return sb;
+
+error_out:
+	sb->s_dev = NODEV;
+	if (UDF_SB_VAT(sb))
+		iput(UDF_SB_VAT(sb));
+	if (!(sb->s_flags & MS_RDONLY))
+		udf_close_lvid(sb);
+	udf_release_data(UDF_SB_LVIDBH(sb));
+	UDF_SB_FREE(sb);
+	unlock_super(sb);
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+void udf_error(struct super_block *sb, const char *function,
+	const char *fmt, ...)
+{
+	va_list args;
+
+	if (!(sb->s_flags & MS_RDONLY))
+	{
+		/* mark sb error */
+		sb->s_dirt = 1;
+	}
+	va_start(args, fmt);
+	vsprintf(error_buf, fmt, args);
+	va_end(args);
+	printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n",
+		bdevname(sb->s_dev), function, error_buf);
+}
+
+void udf_warning(struct super_block *sb, const char *function,
+	const char *fmt, ...)
+{
+	va_list args;
+
+	va_start (args, fmt);
+	vsprintf(error_buf, fmt, args);
+	va_end(args);
+	printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n",
+		bdevname(sb->s_dev), function, error_buf);
+}
+
+/*
+ * udf_put_super
+ *
+ * PURPOSE
+ *	Prepare for destruction of the superblock.
+ *
+ * DESCRIPTION
+ *	Called before the filesystem is unmounted.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static void
+udf_put_super(struct super_block *sb)
+{
+	int i;
+
+	if (UDF_SB_VAT(sb))
+		iput(UDF_SB_VAT(sb));
+	if (!(sb->s_flags & MS_RDONLY))
+		udf_close_lvid(sb);
+	udf_release_data(UDF_SB_LVIDBH(sb));
+	for (i=0; i<UDF_MAX_BLOCK_LOADED; i++)
+		udf_release_data(UDF_SB_BLOCK_BITMAP(sb, i));
+	UDF_SB_FREE(sb);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/*
+ * udf_stat_fs
+ *
+ * PURPOSE
+ *	Return info about the filesystem.
+ *
+ * DESCRIPTION
+ *	Called by sys_statfs()
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+static int
+udf_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
+{
+	int size;
+	struct statfs tmp;
+	int rc;
+
+	size = (bufsize < sizeof(tmp)) ? bufsize: sizeof(tmp);
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.f_type = UDF_SUPER_MAGIC;
+	tmp.f_bsize = sb->s_blocksize;
+	tmp.f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
+	tmp.f_bfree = udf_count_free(sb);
+	tmp.f_bavail = tmp.f_bfree;
+	tmp.f_files = (UDF_SB_LVIDBH(sb) ?
+		(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
+		le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + tmp.f_bfree;
+	tmp.f_ffree = tmp.f_bfree;
+	/* __kernel_fsid_t f_fsid */
+	tmp.f_namelen = UDF_NAME_LEN;
+
+	rc= copy_to_user(buf, &tmp, size) ? -EFAULT: 0;
+	return rc;
+}
+
+static unsigned char udf_bitmap_lookup[16] = {
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+	
+static unsigned int
+udf_count_free(struct super_block *sb)
+{
+	struct buffer_head *bh = NULL;
+	unsigned int accum=0;
+	int index;
+	int block=0, newblock;
+	lb_addr loc;
+	Uint32  bytes;
+	Uint8   value;
+	Uint8 * ptr;
+	Uint16 ident;
+
+	if (UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap == 0xFFFFFFFF)
+	{
+		if (UDF_SB_LVIDBH(sb))
+		{
+			if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
+				accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
+
+			if (accum == 0xFFFFFFFF)
+				accum = 0;
+
+			return accum;
+		}
+		else
+			return 0;
+	}
+	else
+	{
+		struct SpaceBitmapDesc *bm;
+		loc.logicalBlockNum = UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace_bitmap;
+		loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
+		bh = udf_read_ptagged(sb, loc, 0, &ident);
+
+		if (!bh)
+		{
+			printk(KERN_ERR "udf: udf_count_free failed\n");
+			return 0;
+		}
+		else if (ident != TID_SPACE_BITMAP_DESC)
+		{
+			udf_release_data(bh);
+			printk(KERN_ERR "udf: udf_count_free failed\n");
+			return 0;
+		}
+
+		bm = (struct SpaceBitmapDesc *)bh->b_data;
+		bytes = bm->numOfBytes;
+		index = sizeof(struct SpaceBitmapDesc); /* offset in first block only */
+		ptr = (Uint8 *)bh->b_data;
+
+		while ( bytes > 0 )
+		{
+			while ((bytes > 0) && (index < sb->s_blocksize))
+			{
+				value = ptr[index];
+				accum += udf_bitmap_lookup[ value & 0x0f ];
+				accum += udf_bitmap_lookup[ value >> 4 ];
+				index++;
+				bytes--;
+			}
+			if ( bytes )
+			{
+				udf_release_data(bh);
+				newblock = udf_get_lb_pblock(sb, loc, ++block);
+				bh = udf_tread(sb, newblock, sb->s_blocksize);
+				if (!bh)
+				{
+					udf_debug("read failed\n");
+					return accum;
+				}
+				index = 0;
+				ptr = (Uint8 *)bh->b_data;
+			}
+		}
+		udf_release_data(bh);
+		return accum;
+	}
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/symlink.c linux/fs/udf/symlink.c
--- v2.3.16/linux/fs/udf/symlink.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/symlink.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,189 @@
+/*
+ * symlink.c
+ *
+ * PURPOSE
+ *	Symlink handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1998-1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc 
+ *
+ * HISTORY
+ *
+ *  04/16/99 blf  Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/udf_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include "udf_i.h"
+
+static int udf_readlink(struct dentry *, char *, int);
+static struct dentry * udf_follow_link(struct dentry * dentry,
+	struct dentry * base, unsigned int follow);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations udf_symlink_inode_operations = {
+    NULL,			/* no file-operations */
+    NULL,			/* create */
+    NULL,			/* lookup */
+    NULL,			/* link */
+    NULL,			/* unlink */
+    NULL,			/* symlink */
+    NULL,			/* mkdir */
+    NULL,			/* rmdir */
+    NULL,			/* mknod */
+    NULL,			/* rename */
+    udf_readlink,	/* readlink */
+    udf_follow_link,/* follow_link */
+	NULL,			/* get_block */
+    NULL,			/* readpage */
+    NULL,			/* writepage */
+	NULL,			/* flushpage */
+    NULL,			/* truncate */
+    NULL,			/* permission */
+    NULL,			/* smap */
+	NULL			/* revalidate */
+};
+
+int udf_pc_to_char(char *from, int fromlen, char **to)
+{
+	struct PathComponent *pc;
+	int elen = 0, len = 0;
+
+	*to = (char *)kmalloc(fromlen, GFP_KERNEL);
+
+	if (!(*to))
+		return -1;
+
+	while (elen < fromlen)
+	{
+		pc = (struct PathComponent *)(from + elen);
+		if (pc->componentType == 1 && pc->lengthComponentIdent == 0)
+		{
+			(*to)[0] = '/';
+			len = 1;
+		}
+		else if (pc->componentType == 3)
+		{
+			memcpy(&(*to)[len], "../", 3);
+			len += 3;
+		}
+        else if (pc->componentType == 4)
+		{
+			memcpy(&(*to)[len], "./", 2);
+			len += 2;
+		}
+		else if (pc->componentType == 5)
+		{
+			memcpy(&(*to)[len], pc->componentIdent, pc->lengthComponentIdent);
+			len += pc->lengthComponentIdent + 1;
+			(*to)[len-1] = '/';
+		}
+		elen += sizeof(struct PathComponent) + pc->lengthComponentIdent;
+	}
+
+	if (len)
+	{
+		len --;
+		(*to)[len] = '\0';
+	}
+	return len;
+}
+
+static struct dentry * udf_follow_link(struct dentry * dentry,
+	struct dentry * base, unsigned int follow)
+{
+	struct inode *inode = dentry->d_inode;
+	struct buffer_head *bh = NULL;
+	char *symlink, *tmpbuf;
+	int len;
+	
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+		if (!bh)
+			return 0;
+
+		symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
+	}
+	else
+	{
+		bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize);
+
+		if (!bh)
+			return 0;
+
+		symlink = bh->b_data;
+	}
+
+	if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0)
+	{
+		base = lookup_dentry(tmpbuf, base, follow);
+		kfree(tmpbuf);
+		return base;
+	}
+	else
+		return ERR_PTR(-ENOMEM);
+}
+
+static int udf_readlink(struct dentry * dentry, char * buffer, int buflen)
+{
+	struct inode *inode = dentry->d_inode;
+	struct buffer_head *bh = NULL;
+	char *symlink, *tmpbuf;
+	int len;
+	
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_IN_ICB)
+	{
+		bh = udf_tread(inode->i_sb, inode->i_ino, inode->i_sb->s_blocksize);
+
+		if (!bh)
+			return 0;
+
+		symlink = bh->b_data + udf_file_entry_alloc_offset(inode);
+	}
+	else
+	{
+		bh = bread(inode->i_dev, udf_block_map(inode, 0), inode->i_sb->s_blocksize);
+
+		if (!bh)
+			return 0;
+
+		symlink = bh->b_data;
+	}
+
+	if ((len = udf_pc_to_char(symlink, inode->i_size, &tmpbuf)) >= 0)
+	{
+		if (copy_to_user(buffer, tmpbuf, len > buflen ? buflen : len))
+			len = -EFAULT;
+		kfree(tmpbuf);
+	}
+	else
+		len = -ENOMEM;
+
+	UPDATE_ATIME(inode);
+	if (bh)
+		udf_release_data(bh);
+	return len;
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/truncate.c linux/fs/udf/truncate.c
--- v2.3.16/linux/fs/udf/truncate.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/truncate.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,229 @@
+/*
+ * truncate.c
+ *
+ * PURPOSE
+ *	Truncate handling routines for the OSTA-UDF(tm) filesystem.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ *  (C) 1999 Ben Fennema
+ *  (C) 1999 Stelias Computing Inc
+ *
+ * HISTORY
+ *
+ *  02/24/99 blf  Created.
+ *
+ */
+
+#include "udfdecl.h"
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/udf_fs.h>
+
+#include "udf_i.h"
+#include "udf_sb.h"
+
+static void extent_trunc(struct inode * inode, lb_addr bloc, int *extoffset,
+	lb_addr eloc, Uint32 elen, struct buffer_head **bh, Uint32 offset)
+{
+	lb_addr neloc = { 0, 0 };
+	int nelen = 0;
+	int blocks = inode->i_sb->s_blocksize / 512;
+	int last_block = (elen + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize;
+
+
+	if (offset)
+	{
+		nelen = ((offset - 1) << inode->i_sb->s_blocksize_bits) +
+			(inode->i_size & (inode->i_sb->s_blocksize - 1));
+		neloc = eloc;
+	}
+
+	inode->i_blocks -= (blocks * (last_block - offset));
+	udf_write_aext(inode, bloc, extoffset, neloc, nelen, bh, 1);
+	if (!memcmp(&UDF_I_EXT0LOC(inode), &eloc, sizeof(lb_addr)))
+	{
+		UDF_I_EXT0LOC(inode) = neloc;
+		UDF_I_EXT0LEN(inode) = nelen;
+	}
+	mark_inode_dirty(inode);
+	udf_free_blocks(inode, eloc, offset, last_block - offset);
+}
+
+static void trunc(struct inode * inode)
+{
+	lb_addr bloc, eloc, neloc = { 0, 0 };
+	Uint32 extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
+	int etype;
+	int first_block = (inode->i_size + inode->i_sb->s_blocksize - 1) / inode->i_sb->s_blocksize;
+	struct buffer_head *bh = NULL;
+	int adsize;
+
+	if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_SHORT)
+		adsize = sizeof(short_ad);
+	else if (UDF_I_ALLOCTYPE(inode) == ICB_FLAG_AD_LONG)
+		adsize = sizeof(long_ad);
+	else
+		adsize = 0;
+
+	if ((etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh)) != -1)
+	{
+		extoffset -= adsize;
+		extent_trunc(inode, bloc, &extoffset, eloc, elen, &bh, offset);
+
+		if (offset)
+			lenalloc = extoffset;
+		else
+			lenalloc = extoffset - adsize;
+
+		if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+			lenalloc -= udf_file_entry_alloc_offset(inode);
+		else
+			lenalloc -= sizeof(struct AllocExtDesc);
+
+		while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
+		{
+			if (etype == EXTENT_NEXT_EXTENT_ALLOCDECS)
+			{
+				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 0);
+				extoffset = 0;
+				if (lelen)
+				{
+					if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+						memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
+					else
+						memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
+					udf_free_blocks(inode, bloc, 0, lelen);
+				}
+				else
+				{
+					if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+						UDF_I_LENALLOC(inode) = lenalloc;
+					else
+					{
+						struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
+						aed->lengthAllocDescs = cpu_to_le32(lenalloc);
+					}
+				}
+
+				udf_release_data(bh);
+				bh = NULL;
+
+				bloc = eloc;
+				if (elen)
+					lelen = (elen + inode->i_sb->s_blocksize - 1) >>
+						inode->i_sb->s_blocksize_bits;
+				else
+					lelen = 1;
+			}
+			else if (etype != EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+				extent_trunc(inode, bloc, &extoffset, eloc, elen, &bh, 0);
+			else
+				udf_write_aext(inode, bloc, &extoffset, neloc, nelen, &bh, 1);
+		}
+
+		if (lelen)
+		{
+			if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+				memset(bh->b_data, 0x00, udf_file_entry_alloc_offset(inode));
+			else
+				memset(bh->b_data, 0x00, sizeof(struct AllocExtDesc));
+			udf_free_blocks(inode, bloc, 0, lelen);
+		}
+		else
+		{
+			if (!memcmp(&UDF_I_LOCATION(inode), &bloc, sizeof(lb_addr)))
+				UDF_I_LENALLOC(inode) = lenalloc;
+			else
+			{
+				struct AllocExtDesc *aed = (struct AllocExtDesc *)(bh->b_data);
+				aed->lengthAllocDescs = cpu_to_le32(lenalloc);
+			}
+		}
+	}
+	else if (inode->i_size)
+	{
+		lb_addr e0loc = UDF_I_LOCATION(inode);
+		Uint32 ext0offset = udf_file_entry_alloc_offset(inode);
+		char tetype;
+
+		if (offset)
+		{
+			extoffset -= adsize;
+			tetype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
+			if (tetype == EXTENT_NOT_RECORDED_NOT_ALLOCATED)
+			{
+				extoffset -= adsize;
+				elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+					(elen + (offset << inode->i_sb->s_blocksize_bits));
+				if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr)))
+					UDF_I_EXT0LEN(inode) = elen;
+				udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 0);
+			}
+			else
+			{
+				if (elen & (inode->i_sb->s_blocksize - 1))
+				{
+					extoffset -= adsize;
+					elen = (EXTENT_RECORDED_ALLOCATED << 30) |
+						((elen + inode->i_sb->s_blocksize - 1) &
+						~(inode->i_sb->s_blocksize - 1));
+					if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr)))
+						UDF_I_EXT0LEN(inode) = elen;
+					udf_write_aext(inode, bloc, &extoffset, eloc, elen, &bh, 1);
+				}
+				memset(&eloc, 0x00, sizeof(lb_addr));
+				elen = (EXTENT_NOT_RECORDED_NOT_ALLOCATED << 30) |
+					(offset << inode->i_sb->s_blocksize_bits);
+				if (ext0offset == extoffset && !memcmp(&e0loc, &bloc, sizeof(lb_addr)))
+				{
+					UDF_I_EXT0LOC(inode) = eloc;
+					UDF_I_EXT0LEN(inode) = elen;
+				}
+				udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
+			}
+		}
+	}
+
+	udf_release_data(bh);
+}
+
+void udf_truncate(struct inode * inode)
+{
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+			S_ISLNK(inode->i_mode)))
+		return;
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		return;
+
+	if (!UDF_I_EXT0OFFS(inode))
+	{
+		udf_discard_prealloc(inode);
+
+		trunc(inode);
+	}
+
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+}
+
+void udf_truncate_adinicb(struct inode * inode)
+{
+	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+			S_ISLNK(inode->i_mode)))
+		return;
+	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+		return;
+
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty(inode);
+}
diff -u --recursive --new-file v2.3.16/linux/fs/udf/udf_i.h linux/fs/udf/udf_i.h
--- v2.3.16/linux/fs/udf/udf_i.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/udf_i.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,24 @@
+#ifndef __LINUX_UDF_I_H
+#define __LINUX_UDF_I_H
+
+#define UDF_I(X)	(&((X)->u.udf_i))
+
+#define UDF_I_EXT0LOC(X)	( UDF_I(X)->i_ext0Location )
+#define UDF_I_EXT0LEN(X)	( UDF_I(X)->i_ext0Length )
+#define UDF_I_EXT0OFFS(X)	( UDF_I(X)->i_ext0Offset )
+#define UDF_I_LOCATION(X)	( UDF_I(X)->i_location )
+#define UDF_I_LENEATTR(X)	( UDF_I(X)->i_lenEAttr )
+#define UDF_I_LENALLOC(X)	( UDF_I(X)->i_lenAlloc )
+#define UDF_I_UNIQUE(X)		( UDF_I(X)->i_unique )
+#define UDF_I_ALLOCTYPE(X)	( UDF_I(X)->i_alloc_type )
+#define UDF_I_EXTENDED_FE(X)( UDF_I(X)->i_extended_fe )
+#define UDF_I_STRAT4096(X)	( UDF_I(X)->i_strat_4096 )
+#define UDF_I_PREALLOC_COUNT(X)	( UDF_I(X)->i_prealloc_count )
+#define UDF_I_PREALLOC_BLOCK(X)	( UDF_I(X)->i_prealloc_block )
+#define UDF_I_NEXT_ALLOC_BLOCK(X)	( UDF_I(X)->i_next_alloc_block )
+#define UDF_I_NEXT_ALLOC_GOAL(X)	( UDF_I(X)->i_next_alloc_goal )
+#define UDF_I_UATIME(X)		( UDF_I(X)->i_uatime )
+#define UDF_I_UMTIME(X)		( UDF_I(X)->i_umtime )
+#define UDF_I_UCTIME(X)		( UDF_I(X)->i_uctime )
+
+#endif /* !defined(_LINUX_UDF_I_H) */
diff -u --recursive --new-file v2.3.16/linux/fs/udf/udf_sb.h linux/fs/udf/udf_sb.h
--- v2.3.16/linux/fs/udf/udf_sb.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/udf_sb.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,66 @@
+#ifndef __LINUX_UDF_SB_H
+#define __LINUX_UDF_SB_H
+
+#include <linux/udf_167.h>
+#include <linux/udf_udf.h>
+
+/* Since UDF 1.50 is ISO 13346 based... */
+#define UDF_SUPER_MAGIC	0x15013346
+
+#define UDF_FLAG_STRICT		0x00000001U
+#define UDF_FLAG_UNDELETE	0x00000002U
+#define UDF_FLAG_UNHIDE		0x00000004U
+#define UDF_FLAG_VARCONV	0x00000008U
+
+#define UDF_SB_FREE(X)\
+{\
+	if (UDF_SB(X))\
+	{\
+		if (UDF_SB_PARTMAPS(X))\
+			kfree(UDF_SB_PARTMAPS(X));\
+		UDF_SB_PARTMAPS(X) = NULL;\
+	}\
+}
+#define UDF_SB(X)	(&((X)->u.udf_sb))
+
+#define UDF_SB_ALLOC_PARTMAPS(X,Y)\
+{\
+	UDF_SB_NUMPARTS(X) = Y;\
+	UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
+}
+
+#define IS_STRICT(X)			( UDF_SB(X)->s_flags & UDF_FLAG_STRICT )
+#define IS_UNDELETE(X)			( UDF_SB(X)->s_flags & UDF_FLAG_UNDELETE )
+#define IS_UNHIDE(X)			( UDF_SB(X)->s_flags & UDF_FLAG_UNHIDE )
+
+#define UDF_SB_SESSION(X)		( UDF_SB(X)->s_session )
+#define UDF_SB_ANCHOR(X)		( UDF_SB(X)->s_anchor )
+#define UDF_SB_NUMPARTS(X)		( UDF_SB(X)->s_partitions )
+#define UDF_SB_VOLUME(X)		( UDF_SB(X)->s_thisvolume )
+#define UDF_SB_LASTBLOCK(X)		( UDF_SB(X)->s_lastblock )
+#define UDF_SB_VOLDESC(X)		( UDF_SB(X)->s_voldesc )
+#define UDF_SB_LVIDBH(X)		( UDF_SB(X)->s_lvidbh )
+#define UDF_SB_LVID(X)			( (struct LogicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data )
+#define UDF_SB_LVIDIU(X)		( (struct LogicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(sb)->impUse[UDF_SB_LVID(sb)->numOfPartitions * 2 * sizeof(Uint32)/sizeof(Uint8)]) )
+#define UDF_SB_PARTITION(X)		( UDF_SB(X)->s_partition )
+#define UDF_SB_RECORDTIME(X)	( UDF_SB(X)->s_recordtime )
+#define UDF_SB_VOLIDENT(X)		( UDF_SB(X)->s_volident )
+#define UDF_SB_PARTMAPS(X)		( UDF_SB(X)->s_partmaps )
+#define UDF_SB_LOCATION(X)		( UDF_SB(X)->s_location )
+#define UDF_SB_SERIALNUM(X)		( UDF_SB(X)->s_serialnum )
+#define UDF_SB_CHARSET(X)		( UDF_SB(X)->s_nls_iocharset )
+#define UDF_SB_VAT(X)			( UDF_SB(X)->s_vat )
+
+#define UDF_SB_BLOCK_BITMAP_NUMBER(X,Y) ( UDF_SB(X)->s_block_bitmap_number[Y] )
+#define UDF_SB_BLOCK_BITMAP(X,Y)		( UDF_SB(X)->s_block_bitmap[Y] )
+#define UDF_SB_LOADED_BLOCK_BITMAPS(X)	( UDF_SB(X)->s_loaded_block_bitmaps )
+
+#define UDF_SB_PARTTYPE(X,Y)	( UDF_SB_PARTMAPS(X)[Y].s_partition_type )
+#define UDF_SB_PARTROOT(X,Y)	( UDF_SB_PARTMAPS(X)[Y].s_partition_root )
+#define UDF_SB_PARTLEN(X,Y)		( UDF_SB_PARTMAPS(X)[Y].s_partition_len )
+#define UDF_SB_PARTVSN(X,Y)		( UDF_SB_PARTMAPS(X)[Y].s_volumeseqnum )
+#define UDF_SB_PARTNUM(X,Y)		( UDF_SB_PARTMAPS(X)[Y].s_partition_num )
+#define UDF_SB_TYPESPAR(X,Y)	( UDF_SB_PARTMAPS(X)[Y].s_type_specific.s_sparing )
+#define UDF_SB_TYPEVIRT(X,Y)	( UDF_SB_PARTMAPS(X)[Y].s_type_specific.s_virtual )
+
+#endif /* __LINUX_UDF_SB_H */
diff -u --recursive --new-file v2.3.16/linux/fs/udf/udfdecl.h linux/fs/udf/udfdecl.h
--- v2.3.16/linux/fs/udf/udfdecl.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/udfdecl.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,278 @@
+#ifndef __UDF_DECL_H
+#define __UDF_DECL_H
+
+#define UDF_VERSION_NOTICE "v0.8.9"
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/udf_udf.h>
+#include <linux/udf_fs.h>
+#include <linux/config.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,7)
+#error "The UDF Module Current Requires Kernel Version 2.3.7 or greater"
+#endif
+
+/* if we're not defined, we must be compiling outside of the kernel tree */
+#if !defined(CONFIG_UDF_FS) && !defined(CONFIG_UDF_FS_MODULE)
+/* ... so override config */
+#define CONFIG_UDF_FS_MODULE
+#include <linux/fs.h>
+/* explicitly include udf_fs_sb.h and udf_fs_i.h */
+#include <linux/udf_fs_sb.h>
+#include <linux/udf_fs_i.h>
+#else
+#include <linux/fs.h> /* also gets udf_fs_i.h and udf_fs_sb.h */
+#endif
+
+struct dentry;
+struct inode;
+struct task_struct;
+struct buffer_head;
+struct super_block;
+
+extern struct inode_operations udf_dir_inode_operations;
+extern struct inode_operations udf_file_inode_operations;
+extern struct inode_operations udf_file_inode_operations_adinicb;
+extern struct inode_operations udf_symlink_inode_operations;
+
+struct udf_fileident_bh
+{
+	struct buffer_head *sbh;
+	struct buffer_head *ebh;
+	int soffset;
+	int eoffset;
+};
+
+extern void udf_error(struct super_block *, const char *, const char *, ...);
+extern void udf_warning(struct super_block *, const char *, const char *, ...);
+extern int udf_write_fi(struct FileIdentDesc *, struct FileIdentDesc *, struct udf_fileident_bh *, Uint8 *, Uint8 *);
+extern struct dentry * udf_lookup(struct inode *, struct dentry *);
+extern int udf_create(struct inode *, struct dentry *, int);
+extern int udf_mknod(struct inode *, struct dentry *, int, int);
+extern int udf_mkdir(struct inode *, struct dentry *, int);
+extern int udf_rmdir(struct inode *, struct dentry *);
+extern int udf_unlink(struct inode *, struct dentry *);
+extern int udf_symlink(struct inode *, struct dentry *, const char *);
+extern int udf_link(struct dentry *, struct inode *, struct dentry *);
+extern int udf_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern struct inode *udf_iget(struct super_block *, lb_addr);
+extern int udf_sync_inode(struct inode *);
+extern struct buffer_head * udf_expand_adinicb(struct inode *, int *, int, int *);
+extern struct buffer_head * udf_getblk(struct inode *, long, int, int *);
+extern int udf_get_block(struct inode *, long, struct buffer_head *, int);
+extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
+extern void udf_read_inode(struct inode *);
+extern void udf_put_inode(struct inode *);
+extern void udf_delete_inode(struct inode *);
+extern void udf_write_inode(struct inode *);
+extern long udf_locked_block_map(struct inode *, long);
+extern long udf_block_map(struct inode *, long);
+extern int inode_bmap(struct inode *, int, lb_addr *, Uint32 *, lb_addr *, Uint32 *, Uint32 *, struct buffer_head **);
+extern int udf_add_aext(struct inode *, lb_addr *, int *, lb_addr, Uint32, struct buffer_head **, int);
+extern int udf_write_aext(struct inode *, lb_addr, int *, lb_addr, Uint32, struct buffer_head **, int);
+extern int udf_insert_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
+extern int udf_delete_aext(struct inode *, lb_addr, int, lb_addr, Uint32, struct buffer_head *);
+extern int udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
+extern int udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, Uint32 *, struct buffer_head **, int);
+
+extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref);
+
+extern struct buffer_head *udf_tread(struct super_block *, int, int);
+extern struct GenericAttrFormat *udf_add_extendedattr(struct inode *, Uint32, Uint32, Uint8, struct buffer_head **);
+extern struct GenericAttrFormat *udf_get_extendedattr(struct inode *, Uint32, Uint8, struct buffer_head **);
+extern struct buffer_head *udf_read_tagged(struct super_block *, Uint32, Uint32, Uint16 *);
+extern struct buffer_head *udf_read_ptagged(struct super_block *, lb_addr, Uint32, Uint16 *);
+extern struct buffer_head *udf_read_untagged(struct super_block *, Uint32, Uint32);
+extern void udf_release_data(struct buffer_head *);
+
+extern unsigned int udf_get_last_session(kdev_t);
+extern unsigned int udf_get_last_block(kdev_t, int *);
+
+extern Uint32 udf_get_pblock(struct super_block *, Uint32, Uint16, Uint32);
+extern Uint32 udf_get_lb_pblock(struct super_block *, lb_addr, Uint32);
+
+extern int udf_get_filename(Uint8 *, Uint8 *, int);
+
+extern void udf_free_inode(struct inode *);
+extern struct inode * udf_new_inode (const struct inode *, int, int *);
+extern void udf_discard_prealloc(struct inode *);
+extern void udf_truncate(struct inode *);
+extern void udf_truncate_adinicb(struct inode *);
+extern void udf_free_blocks(const struct inode *, lb_addr, Uint32, Uint32);
+extern int udf_alloc_blocks(const struct inode *, Uint16, Uint32, Uint32);
+extern int udf_new_block(const struct inode *, Uint16, Uint32, int *);
+extern int udf_sync_file(struct file *, struct dentry *);
+
+#else
+
+#include <sys/types.h>
+#include <linux/udf_udf.h>
+
+#endif /* __KERNEL__ */
+
+#include "udfend.h"
+
+/* structures */
+struct udf_directory_record
+{
+	Uint32	d_parent;
+	Uint32	d_inode;
+	Uint32	d_name[255];
+};
+
+#define VDS_POS_PRIMARY_VOL_DESC	0
+#define VDS_POS_UNALLOC_SPACE_DESC	1
+#define VDS_POS_LOGICAL_VOL_DESC	2
+#define VDS_POS_PARTITION_DESC		3
+#define VDS_POS_IMP_USE_VOL_DESC	4
+#define VDS_POS_VOL_DESC_PTR		5
+#define VDS_POS_TERMINATING_DESC	6
+#define VDS_POS_LENGTH				7
+
+struct udf_vds_record
+{
+	Uint32 block;
+	Uint32 volDescSeqNum;
+};
+
+struct ktm
+{
+	int tm_sec;
+	int tm_min;
+	int tm_hour;
+	int tm_mday;
+	int tm_mon;
+	int tm_year;
+	int tm_isdst;
+};
+
+struct ustr
+{
+	Uint8 u_cmpID;
+	Uint8 u_name[UDF_NAME_LEN-1];
+	Uint8 u_len;
+	Uint8 padding;
+	unsigned long u_hash;
+};
+
+
+#define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
+#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
+
+#ifdef __KERNEL__
+
+#define CURRENT_UTIME	(xtime.tv_usec)
+
+#define udf_file_entry_alloc_offset(inode)\
+	((UDF_I_EXTENDED_FE(inode) ?\
+		sizeof(struct ExtendedFileEntry) :\
+		sizeof(struct FileEntry)) + UDF_I_LENEATTR(inode))
+
+#define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
+#define udf_set_bit(nr,addr) ext2_set_bit(nr,addr)
+#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
+#define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size)
+#define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset)
+
+#define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
+#define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)
+#define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))
+
+extern inline int find_next_one_bit (void * addr, int size, int offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset / BITS_PER_LONG);
+	unsigned long result = offset & ~(BITS_PER_LONG-1);
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= (BITS_PER_LONG-1);
+	if (offset)
+	{
+		tmp = leBPL_to_cpup(p++);
+		tmp &= ~0UL << offset;
+		if (size < BITS_PER_LONG)
+			goto found_first;
+		if (tmp)
+			goto found_middle;
+		size -= BITS_PER_LONG;
+		result += BITS_PER_LONG;
+	}
+	while (size & ~(BITS_PER_LONG-1))
+	{
+		if ((tmp = leBPL_to_cpup(p++)))
+			goto found_middle;
+		result += BITS_PER_LONG;
+		size -= BITS_PER_LONG;
+	}
+	if (!size)
+		return result;
+	tmp = leBPL_to_cpup(p);
+found_first:
+	tmp &= ~0UL >> (BITS_PER_LONG-size);
+found_middle:
+	return result + ffz(~tmp);
+}
+
+#define find_first_one_bit(addr, size)\
+	find_next_one_bit((addr), (size), 0)
+
+#endif
+
+/* Miscellaneous UDF Prototypes */
+
+extern int udf_ustr_to_dchars(Uint8 *, const struct ustr *, int);
+extern int udf_ustr_to_char(Uint8 *, const struct ustr *, int);
+extern int udf_ustr_to_dstring(dstring *, const struct ustr *, int);
+extern int udf_dchars_to_ustr(struct ustr *, const Uint8 *, int);
+extern int udf_char_to_ustr(struct ustr *, const Uint8 *, int);
+extern int udf_dstring_to_ustr(struct ustr *, const dstring *, int);
+
+extern Uint16 udf_crc(Uint8 *, Uint32, Uint16);
+extern int udf_translate_to_linux(Uint8 *, Uint8 *, int, Uint8 *, int);
+extern int udf_build_ustr(struct ustr *, dstring *, int);
+extern int udf_build_ustr_exact(struct ustr *, dstring *, int);
+extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
+extern int udf_UTF8toCS0(dstring *, struct ustr *, int);
+
+extern uid_t  udf_convert_uid(int);
+extern gid_t  udf_convert_gid(int);
+extern Uint32 udf64_low32(Uint64);
+extern Uint32 udf64_high32(Uint64);
+
+
+extern time_t *udf_stamp_to_time(time_t *, timestamp);
+extern timestamp *udf_time_to_stamp(timestamp *, time_t, long);
+extern time_t udf_converttime (struct ktm *);
+
+#ifdef __KERNEL__
+extern Uint8 *
+udf_filead_read(struct inode *, Uint8 *, Uint8, lb_addr, int *, int *,
+	struct buffer_head **, int *);
+
+extern struct FileIdentDesc *
+udf_fileident_read(struct inode *, int *,
+	struct udf_fileident_bh *,
+	struct FileIdentDesc *,
+	lb_addr *, Uint32 *,
+	Uint32 *, struct buffer_head **);
+#endif
+extern struct FileIdentDesc * 
+udf_get_fileident(void * buffer, int bufsize, int * offset);
+extern extent_ad * udf_get_fileextent(void * buffer, int bufsize, int * offset);
+extern long_ad * udf_get_filelongad(void * buffer, int bufsize, int * offset, int);
+extern short_ad * udf_get_fileshortad(void * buffer, int bufsize, int * offset, int);
+extern Uint8 * udf_get_filead(struct FileEntry *, Uint8 *, int, int, int, int *);
+
+extern void udf_update_tag(char *, int);
+extern void udf_new_tag(char *, Uint16, Uint16, Uint16, Uint32, int);
+
+#endif
diff -u --recursive --new-file v2.3.16/linux/fs/udf/udfend.h linux/fs/udf/udfend.h
--- v2.3.16/linux/fs/udf/udfend.h	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/udfend.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,107 @@
+#ifndef __UDF_ENDIAN_H
+#define __UDF_ENDIAN_H
+
+#ifndef __KERNEL__ 
+
+#if __BYTE_ORDER == 0
+
+#error "__BYTE_ORDER must be defined"
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+#define le16_to_cpu(x) \
+	((Uint16)((((Uint16)(x) & 0x00FFU) << 8) | \
+		  (((Uint16)(x) & 0xFF00U) >> 8)))
+ 
+#define le32_to_cpu(x) \
+	((Uint32)((((Uint32)(x) & 0x000000FFU) << 24) | \
+		  (((Uint32)(x) & 0x0000FF00U) <<  8) | \
+		  (((Uint32)(x) & 0x00FF0000U) >>  8) | \
+		  (((Uint32)(x) & 0xFF000000U) >> 24)))
+
+#define le64_to_cpu(x) \
+	((Uint64)((((Uint64)(x) & 0x00000000000000FFULL) << 56) | \
+		  (((Uint64)(x) & 0x000000000000FF00ULL) << 40) | \
+		  (((Uint64)(x) & 0x0000000000FF0000ULL) << 24) | \
+		  (((Uint64)(x) & 0x00000000FF000000ULL) <<  8) | \
+		  (((Uint64)(x) & 0x000000FF00000000ULL) >>  8) | \
+		  (((Uint64)(x) & 0x0000FF0000000000ULL) >> 24) | \
+		  (((Uint64)(x) & 0x00FF000000000000ULL) >> 40) | \
+		  (((Uint64)(x) & 0xFF00000000000000ULL) >> 56)))		
+
+#define cpu_to_le16(x) (le16_to_cpu(x))
+#define cpu_to_le32(x) (le32_to_cpu(x))
+#define cpu_to_le64(x) (le64_to_cpu(x))
+
+#else /* __BYTE_ORDER == __LITTLE_ENDIAN */
+
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
+
+#endif
+
+#endif
+
+static inline lb_addr lelb_to_cpu(lb_addr in)
+{
+	lb_addr out;
+	out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
+	out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
+	return out;
+}
+
+static inline lb_addr cpu_to_lelb(lb_addr in)
+{
+	lb_addr out;
+	out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
+	out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
+	return out;
+}
+
+static inline timestamp lets_to_cpu(timestamp in)
+{
+	timestamp out;
+	memcpy(&out, &in, sizeof(timestamp));
+	out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
+	out.year = le16_to_cpu(in.year);
+	return out;
+}
+
+static inline long_ad lela_to_cpu(long_ad in)
+{
+	long_ad out;
+	out.extLength = le32_to_cpu(in.extLength);
+	out.extLocation = lelb_to_cpu(in.extLocation);
+	return out;
+}
+
+static inline long_ad cpu_to_lela(long_ad in)
+{
+	long_ad out;
+	out.extLength = cpu_to_le32(in.extLength);
+	out.extLocation = cpu_to_lelb(in.extLocation);
+	return out;
+}
+
+static inline extent_ad leea_to_cpu(extent_ad in)
+{
+	extent_ad out;
+	out.extLength = le32_to_cpu(in.extLength);
+	out.extLocation = le32_to_cpu(in.extLocation);
+	return out;
+}
+
+static inline timestamp cpu_to_lets(timestamp in)
+{
+	timestamp out;
+	memcpy(&out, &in, sizeof(timestamp));
+	out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
+	out.year = cpu_to_le16(in.year);
+	return out;
+}
+
+#endif /* __UDF_ENDIAN_H */
diff -u --recursive --new-file v2.3.16/linux/fs/udf/udftime.c linux/fs/udf/udftime.c
--- v2.3.16/linux/fs/udf/udftime.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/udftime.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,373 @@
+/* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Paul Eggert (eggert@twinsun.com).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/*
+ * dgb 10/2/98: ripped this from glibc source to help convert timestamps to unix time 
+ *     10/4/98: added new table-based lookup after seeing how ugly the gnu code is
+ */
+
+/* Assume that leap seconds are possible, unless told otherwise.
+   If the host has a `zic' command with a `-L leapsecondfilename' option,
+   then it supports leap seconds; otherwise it probably doesn't.  */
+#ifndef LEAP_SECONDS_POSSIBLE
+#define LEAP_SECONDS_POSSIBLE 1
+#endif
+
+#if defined(__linux__) && defined(__KERNEL__)
+#include <linux/types.h>
+#include <linux/kernel.h>
+#else
+#include <stdio.h>
+#include <sys/types.h>
+#endif
+
+#include "udfdecl.h"
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#ifndef INT_MIN
+#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
+#endif
+#ifndef INT_MAX
+#define INT_MAX (~0 - INT_MIN)
+#endif
+
+#ifndef TIME_T_MIN
+#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
+		    : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
+#endif
+#ifndef TIME_T_MAX
+#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
+#endif
+
+#define TM_YEAR_BASE 1900
+#define EPOCH_YEAR 1970
+
+#ifndef __isleap
+/* Nonzero if YEAR is a leap year (every 4 years,
+   except every 100th isn't, and every 400th is).  */
+#define	__isleap(year)	\
+  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
+#endif
+
+/* How many days come before each month (0-12).  */
+const unsigned short int __mon_yday[2][13] =
+  {
+    /* Normal years.  */
+    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+    /* Leap years.  */
+    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+  };
+
+time_t udf_converttime (struct ktm *);
+#ifndef USE_GNU_MKTIME_METHOD
+
+#define MAX_YEAR_SECONDS	68
+
+time_t year_seconds[MAX_YEAR_SECONDS]= {
+	0, 
+	/*1971:*/ 31554000, /*1972:*/ 63090000, /*1973:*/ 94712400,
+ 	/*1974:*/ 126248400, /*1975:*/ 157784400, /*1976:*/ 189320400,
+ 	/*1977:*/ 220942800, /*1978:*/ 252478800, /*1979:*/ 284014800,
+ 	/*1980:*/ 315550800, /*1981:*/ 347173200, /*1982:*/ 378709200,
+ 	/*1983:*/ 410245200, /*1984:*/ 441781200, /*1985:*/ 473403600,
+ 	/*1986:*/ 504939600, /*1987:*/ 536475600, /*1988:*/ 568011600,
+ 	/*1989:*/ 599634000, /*1990:*/ 631170000, /*1991:*/ 662706000,
+ 	/*1992:*/ 694242000, /*1993:*/ 725864400, /*1994:*/ 757400400,
+ 	/*1995:*/ 788936400, /*1996:*/ 820472400, /*1997:*/ 852094800,
+ 	/*1998:*/ 883630800, /*1999:*/ 915166800, /*2000:*/ 946702800,
+ 	/*2001:*/ 978325200, /*2002:*/ 1009861200, /*2003:*/ 1041397200,
+ 	/*2004:*/ 1072933200, /*2005:*/ 1104555600, /*2006:*/ 1136091600,
+ 	/*2007:*/ 1167627600, /*2008:*/ 1199163600, /*2009:*/ 1230786000,
+ 	/*2010:*/ 1262322000, /*2011:*/ 1293858000, /*2012:*/ 1325394000,
+ 	/*2013:*/ 1357016400, /*2014:*/ 1388552400, /*2015:*/ 1420088400,
+ 	/*2016:*/ 1451624400, /*2017:*/ 1483246800, /*2018:*/ 1514782800,
+ 	/*2019:*/ 1546318800, /*2020:*/ 1577854800, /*2021:*/ 1609477200,
+ 	/*2022:*/ 1641013200, /*2023:*/ 1672549200, /*2024:*/ 1704085200,
+ 	/*2025:*/ 1735707600, /*2026:*/ 1767243600, /*2027:*/ 1798779600,
+ 	/*2028:*/ 1830315600, /*2029:*/ 1861938000, /*2030:*/ 1893474000,
+ 	/*2031:*/ 1925010000, /*2032:*/ 1956546000, /*2033:*/ 1988168400,
+ 	/*2034:*/ 2019704400, /*2035:*/ 2051240400, /*2036:*/ 2082776400,
+ 	/*2037:*/ 2114398800
+};
+
+time_t udf_converttime (struct ktm *tm)
+{
+    time_t r;
+    int yday;
+
+	if ( !tm )
+		return -1;
+	if ( (tm->tm_year+TM_YEAR_BASE < EPOCH_YEAR) || 
+		 (tm->tm_year+TM_YEAR_BASE > EPOCH_YEAR+MAX_YEAR_SECONDS) )
+		return -1;
+	r = year_seconds[tm->tm_year-70];
+
+	yday = ((__mon_yday[__isleap (tm->tm_year + TM_YEAR_BASE)]
+	       [tm->tm_mon-1])
+	      + tm->tm_mday - 1);
+	r += ( ( (yday* 24) + (tm->tm_hour-1) ) * 60 + tm->tm_min ) * 60 + tm->tm_sec;
+	return r;
+}
+
+#ifdef __KERNEL__
+
+extern struct timezone sys_tz;
+
+#define SECS_PER_HOUR   (60 * 60)
+#define SECS_PER_DAY    (SECS_PER_HOUR * 24)
+
+timestamp *
+udf_time_to_stamp(timestamp *dest, time_t tv_sec, long tv_usec)
+{
+	long int days, rem, y;
+	const unsigned short int *ip;
+	int offset = (-sys_tz.tz_minuteswest + (sys_tz.tz_dsttime ? 60 : 0));
+
+    if (!dest)
+        return NULL;
+
+	dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF);
+
+	tv_sec += offset * 60;
+	days = tv_sec / SECS_PER_DAY;
+	rem = tv_sec % SECS_PER_DAY;
+	dest->hour = rem / SECS_PER_HOUR;
+	rem %= SECS_PER_HOUR;
+	dest->minute = rem / 60;
+	dest->second = rem % 60;
+	y = 1970;
+
+#define DIV(a,b) ((a) / (b) - ((a) % (b) < 0))
+#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+
+	while (days < 0 || days >= (__isleap(y) ? 366 : 365))
+	{
+		long int yg = y + days / 365 - (days % 365 < 0);
+
+		/* Adjust DAYS and Y to match the guessed year.  */
+		days -= ((yg - y) * 365
+			+ LEAPS_THRU_END_OF (yg - 1)
+			- LEAPS_THRU_END_OF (y - 1));
+		y = yg;
+	}
+	dest->year = y;
+	ip = __mon_yday[__isleap(y)];
+	for (y = 11; days < (long int) ip[y]; --y)
+		continue;
+	days -= ip[y];
+	dest->month = y + 1;
+	dest->day = days + 1;
+
+	dest->centiseconds = tv_usec / 10000;
+	dest->hundredsOfMicroseconds = (tv_usec - dest->centiseconds * 10000) / 100;
+	dest->microseconds = (tv_usec - dest->centiseconds * 10000 -
+		dest->hundredsOfMicroseconds * 100);
+    return dest;
+}
+#endif
+
+#else
+
+static time_t ydhms_tm_diff (int, int, int, int, int, const struct ktm *);
+
+
+/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
+   measured in seconds, ignoring leap seconds.
+   YEAR uses the same numbering as TM->tm_year.
+   All values are in range, except possibly YEAR.
+   If overflow occurs, yield the low order bits of the correct answer.  */
+static time_t
+ydhms_tm_diff (int year, int yday, int hour, int min, int sec, const struct ktm *tp)
+{
+  time_t result;
+
+  /* Compute intervening leap days correctly even if year is negative.
+     Take care to avoid int overflow.  time_t overflow is OK, since
+     only the low order bits of the correct time_t answer are needed.
+     Don't convert to time_t until after all divisions are done, since
+     time_t might be unsigned.  */
+  int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
+  int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
+  int a100 = a4 / 25 - (a4 % 25 < 0);
+  int b100 = b4 / 25 - (b4 % 25 < 0);
+  int a400 = a100 >> 2;
+  int b400 = b100 >> 2;
+  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
+  time_t years = year - (time_t) tp->tm_year;
+  time_t days = (365 * years + intervening_leap_days);
+  result= (60 * (60 * (24 * days + (hour - tp->tm_hour))
+		+ (min - tp->tm_min))
+	  + (sec - tp->tm_sec));
+#ifdef __KERNEL__
+  printk(KERN_ERR "udf: ydhms_tm_diff(%d,%d,%d,%d,%d,) returning %ld\n",
+	year, yday, hour, min, sec, result);
+#endif
+  return result;
+}
+
+
+/* Convert *TP to a time_t value, inverting
+   the monotonic and mostly-unit-linear conversion function CONVERT.
+   Use *OFFSET to keep track of a guess at the offset of the result,
+   compared to what the result would be for UTC without leap seconds.
+   If *OFFSET's guess is correct, only one CONVERT call is needed.  */
+time_t
+udf_converttime (struct ktm *tp)
+{
+  time_t t, dt, t0;
+  struct ktm tm;
+
+  /* The maximum number of probes (calls to CONVERT) should be enough
+     to handle any combinations of time zone rule changes, solar time,
+     and leap seconds.  Posix.1 prohibits leap seconds, but some hosts
+     have them anyway.  */
+  int remaining_probes = 4;
+
+  /* Time requested.  Copy it in case CONVERT modifies *TP; this can
+     occur if TP is localtime's returned value and CONVERT is localtime.  */
+  int sec = tp->tm_sec;
+  int min = tp->tm_min;
+  int hour = tp->tm_hour;
+  int mday = tp->tm_mday;
+  int mon = tp->tm_mon;
+  int year_requested = tp->tm_year;
+  int isdst = tp->tm_isdst;
+
+  /* Ensure that mon is in range, and set year accordingly.  */
+  int mon_remainder = mon % 12;
+  int negative_mon_remainder = mon_remainder < 0;
+  int mon_years = mon / 12 - negative_mon_remainder;
+  int year = year_requested + mon_years;
+
+  /* The other values need not be in range:
+     the remaining code handles minor overflows correctly,
+     assuming int and time_t arithmetic wraps around.
+     Major overflows are caught at the end.  */
+
+  /* Calculate day of year from year, month, and day of month.
+     The result need not be in range.  */
+  int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
+	       [mon_remainder + 12 * negative_mon_remainder])
+	      + mday - 1);
+
+#if LEAP_SECONDS_POSSIBLE
+  /* Handle out-of-range seconds specially,
+     since ydhms_tm_diff assumes every minute has 60 seconds.  */
+  int sec_requested = sec;
+  if (sec < 0)
+    sec = 0;
+  if (59 < sec)
+    sec = 59;
+#endif
+
+  /* Invert CONVERT by probing.  First assume the same offset as last time.
+     Then repeatedly use the error to improve the guess.  */
+
+  tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
+  tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+  /*
+  t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
+
+  for (t = t0; 
+       (dt = ydhms_tm_diff (year, yday, hour, min, sec, &tm));
+       t += dt)
+    if (--remaining_probes == 0)
+      return -1;
+  */
+
+  /* Check whether tm.tm_isdst has the requested value, if any.  */
+  if (0 <= isdst && 0 <= tm.tm_isdst)
+    {
+      int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
+      if (dst_diff)
+	{
+	  /* Move two hours in the direction indicated by the disagreement,
+	     probe some more, and switch to a new time if found.
+	     The largest known fallback due to daylight savings is two hours:
+	     once, in Newfoundland, 1988-10-30 02:00 -> 00:00.  */
+	  time_t ot = t - 2 * 60 * 60 * dst_diff;
+	  while (--remaining_probes != 0)
+	    {
+	      struct ktm otm;
+	      if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
+					 &otm)))
+		{
+		  t = ot;
+		  tm = otm;
+		  break;
+		}
+	      if ((ot += dt) == t)
+		break;  /* Avoid a redundant probe.  */
+	    }
+	}
+    }
+
+
+#if LEAP_SECONDS_POSSIBLE
+  if (sec_requested != tm.tm_sec)
+    {
+      /* Adjust time to reflect the tm_sec requested, not the normalized value.
+	 Also, repair any damage from a false match due to a leap second.  */
+      t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
+    }
+#endif
+
+  if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
+    {
+      /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
+	 so check for major overflows.  A gross check suffices,
+	 since if t has overflowed, it is off by a multiple of
+	 TIME_T_MAX - TIME_T_MIN + 1.  So ignore any component of
+	 the difference that is bounded by a small value.  */
+
+      double dyear = (double) year_requested + mon_years - tm.tm_year;
+      double dday = 366 * dyear + mday;
+      double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
+
+      if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
+	return -1;
+    }
+
+  *tp = tm;
+#ifdef __KERNEL__
+  udf_debug("returning %ld\n", t);
+#endif
+  return t;
+}
+#endif
+
+#ifdef INCLUDE_PRINT_KTM
+static void
+print_ktm (struct ktm *tp)
+{
+#ifdef __KERNEL__
+  udf_debug(
+#else
+  printf(
+#endif
+	"%04d-%02d-%02d %02d:%02d:%02d isdst %d",
+	  tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
+	  tp->tm_hour, tp->tm_min, tp->tm_sec, tp->tm_isdst);
+}
+#endif
+
+/* EOF */
diff -u --recursive --new-file v2.3.16/linux/fs/udf/unicode.c linux/fs/udf/unicode.c
--- v2.3.16/linux/fs/udf/unicode.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/udf/unicode.c	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,447 @@
+/*
+ * unicode.c
+ *
+ * PURPOSE
+ *	Routines for converting between UTF-8 and OSTA Compressed Unicode.
+ *      Also handles filename mangling
+ *
+ * DESCRIPTION
+ *	OSTA Compressed Unicode is explained in the OSTA UDF specification.
+ *		http://www.osta.org/
+ *	UTF-8 is explained in the IETF RFC XXXX.
+ *		ftp://ftp.internic.net/rfc/rfcxxxx.txt
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team's mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ */
+
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/string.h>       /* for memset */
+#include <linux/udf_fs.h>
+#else
+#include <string.h>
+#endif
+
+#include "udfdecl.h"
+
+int udf_ustr_to_dchars(Uint8 *dest, const struct ustr *src, int strlen)
+{
+	if ( (!dest) || (!src) || (!strlen) || (src->u_len > strlen) )
+		return 0;
+	memcpy(dest+1, src->u_name, src->u_len-1);
+	dest[0] = src->u_cmpID;
+	return src->u_len;
+}
+
+int udf_ustr_to_char(Uint8 *dest, const struct ustr *src, int strlen)
+{
+	if ( (!dest) || (!src) || (!strlen) || (src->u_len >= strlen) )
+		return 0;
+	memcpy(dest, src->u_name, src->u_len-1);
+	return src->u_len - 1;
+}
+
+int udf_ustr_to_dstring(dstring *dest, const struct ustr *src, int dlength)
+{
+	if ( udf_ustr_to_dchars(dest, src, dlength-1) )
+	{
+		dest[dlength-1] = src->u_len;
+		return dlength;
+	}
+	else
+		return 0;
+}
+
+int udf_dchars_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
+{
+	if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN) )
+		return 0;
+	memset(dest, 0, sizeof(struct ustr));
+	memcpy(dest->u_name, src+1, strlen-1);
+	dest->u_cmpID = src[0];
+	dest->u_len = strlen;
+	return strlen;
+}
+
+int udf_char_to_ustr(struct ustr *dest, const Uint8 *src, int strlen)
+{
+	if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) )
+		return 0;
+	memset(dest, 0, sizeof(struct ustr));
+	memcpy(dest->u_name, src, strlen);
+	dest->u_cmpID = 0x08;
+	dest->u_len = strlen + 1;
+	return strlen + 1;
+}
+
+
+int udf_dstring_to_ustr(struct ustr *dest, const dstring *src, int dlength)
+{
+	if ( dlength && udf_dchars_to_ustr(dest, src, src[dlength-1]) )
+		return dlength;
+	else
+		return 0;
+}
+
+/*
+ * udf_build_ustr
+ */
+int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
+{
+    int usesize;
+
+	if ( (!dest) || (!ptr) || (!size) )
+		return -1;
+
+	memset(dest, 0, sizeof(struct ustr));
+	usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
+	dest->u_cmpID=ptr[0];
+	dest->u_len=ptr[size-1];
+	memcpy(dest->u_name, ptr+1, usesize-1);
+	return 0;
+}
+
+/*
+ * udf_build_ustr_exact
+ */
+int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
+{
+    if ( (!dest) || (!ptr) || (!exactsize) )
+	return -1;
+
+    memset(dest, 0, sizeof(struct ustr));
+    dest->u_cmpID=ptr[0];
+    dest->u_len=exactsize-1;
+    memcpy(dest->u_name, ptr+1, exactsize-1);
+    return 0;
+}
+
+/*
+ * udf_ocu_to_udf8
+ *
+ * PURPOSE
+ *	Convert OSTA Compressed Unicode to the UTF-8 equivalent.
+ *
+ * DESCRIPTION
+ *	This routine is only called by udf_filldir().
+ *
+ * PRE-CONDITIONS
+ *	utf			Pointer to UTF-8 output buffer.
+ *	ocu			Pointer to OSTA Compressed Unicode input buffer
+ *				of size UDF_NAME_LEN bytes.
+ * 				both of type "struct ustr *"
+ *
+ * POST-CONDITIONS
+ *	<return>		Zero on success.
+ *
+ * HISTORY
+ *	November 12, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
+{
+	Uint8 *ocu;
+	Uint32 c;
+	Uint8 cmp_id, ocu_len;
+	int i;
+
+	ocu = ocu_i->u_name;
+
+	ocu_len = ocu_i->u_len;
+	cmp_id = ocu_i->u_cmpID;
+	utf_o->u_len = 0;
+
+	if (ocu_len == 0)
+	{
+		memset(utf_o, 0, sizeof(struct ustr));
+		utf_o->u_cmpID = 0;
+		utf_o->u_len = 0;
+		return 0;
+	}
+
+	if ((cmp_id != 8) && (cmp_id != 16))
+	{
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+#endif
+		return 0;
+	}
+
+	for (i = 0; (i < ocu_len) && (utf_o->u_len < UDF_NAME_LEN) ;) {
+
+		/* Expand OSTA compressed Unicode to Unicode */
+		c = ocu[i++];
+		if (cmp_id == 16)
+		{
+			c = (c << 8) | ocu[i++];
+#ifdef __KERNEL__
+			if (c & 0xFF00)
+				udf_debug("cmd_id == 16 (0x%2x%2x)\n",
+					((c >> 8) & 0xFF), (c & 0xFF));
+#endif
+		}
+
+		/* Compress Unicode to UTF-8 */
+		if (c < 0x80U)
+			utf_o->u_name[utf_o->u_len++] = (Uint8)c;
+		else if (c < 0x800U) {
+			utf_o->u_name[utf_o->u_len++] = (Uint8)(0xc0 | (c >> 6));
+			utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | (c & 0x3f));
+#ifdef __KERNEL__
+			udf_debug("(0x%2x%2x) -> (%2x) (%2x)\n",
+				((c >> 8) & 0xFF), (c & 0xFF),
+				utf_o->u_name[utf_o->u_len-2],
+				utf_o->u_name[utf_o->u_len-1]);
+#endif
+		} else {
+			utf_o->u_name[utf_o->u_len++] = (Uint8)(0xe0 | (c >> 12));
+			utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | ((c >> 6) & 0x3f));
+			utf_o->u_name[utf_o->u_len++] = (Uint8)(0x80 | (c & 0x3f));
+#ifdef __KERNEL__
+			udf_debug("(0x%2x%2x) -> (%2x) (%2x) (%2x)\n",
+				((c >> 8) & 0xFF), (c & 0xFF),
+				utf_o->u_name[utf_o->u_len-3],
+				utf_o->u_name[utf_o->u_len-2],
+				utf_o->u_name[utf_o->u_len-1]);
+#endif
+		}
+	}
+	utf_o->u_cmpID=8;
+	utf_o->u_hash=0L;
+	utf_o->padding=0;
+
+	return utf_o->u_len;
+}
+
+/*
+ *
+ * udf_utf8_to_ocu
+ *
+ * PURPOSE
+ *	Convert UTF-8 to the OSTA Compressed Unicode equivalent.
+ *
+ * DESCRIPTION
+ *	This routine is only called by udf_lookup().
+ *
+ * PRE-CONDITIONS
+ *	ocu			Pointer to OSTA Compressed Unicode output
+ *				buffer of size UDF_NAME_LEN bytes.
+ *	utf			Pointer to UTF-8 input buffer.
+ *	utf_len			Length of UTF-8 input buffer in bytes.
+ *
+ * POST-CONDITIONS
+ *	<return>		Zero on success.
+ *
+ * HISTORY
+ *	November 12, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ */
+int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length)
+{
+	unsigned c, i, max_val, utf_char;
+	int utf_cnt;
+	int u_len = 0;
+
+	memset(ocu, 0, sizeof(dstring) * length);
+	ocu[0] = 8;
+	max_val = 0xffU;
+
+try_again:
+	utf_char = 0U;
+	utf_cnt = 0U;
+	for (i = 0U; i < utf->u_len; i++) {
+		c = (unsigned)utf->u_name[i];
+
+		/* Complete a multi-byte UTF-8 character */
+		if (utf_cnt) {
+			utf_char = (utf_char << 6) | (c & 0x3fU);
+			if (--utf_cnt)
+				continue;
+		} else {
+			/* Check for a multi-byte UTF-8 character */
+			if (c & 0x80U) {
+				/* Start a multi-byte UTF-8 character */
+				if ((c & 0xe0U) == 0xc0U) {
+					utf_char = c & 0x1fU;
+					utf_cnt = 1;
+				} else if ((c & 0xf0U) == 0xe0U) {
+					utf_char = c & 0x0fU;
+					utf_cnt = 2;
+				} else if ((c & 0xf8U) == 0xf0U) {
+					utf_char = c & 0x07U;
+					utf_cnt = 3;
+				} else if ((c & 0xfcU) == 0xf8U) {
+					utf_char = c & 0x03U;
+					utf_cnt = 4;
+				} else if ((c & 0xfeU) == 0xfcU) {
+					utf_char = c & 0x01U;
+					utf_cnt = 5;
+				} else
+					goto error_out;
+				continue;
+			} else
+				/* Single byte UTF-8 character (most common) */
+				utf_char = c;
+		}
+
+		/* Choose no compression if necessary */
+		if (utf_char > max_val) {
+			if ( 0xffU == max_val ) {
+				max_val = 0xffffU;
+				ocu[0] = (Uint8)0x10U;
+				goto try_again;
+			}
+			goto error_out;
+		}
+
+		if (max_val == 0xffffU)
+			ocu[++u_len] = (Uint8)(utf_char >> 8);
+		ocu[++u_len] = (Uint8)(utf_char & 0xffU);
+	}
+
+	if (utf_cnt) {
+error_out:
+#ifdef __KERNEL__
+		printk(KERN_ERR "udf: bad UTF-8 character\n");
+#endif
+		return 0;
+	}
+
+	ocu[length - 1] = (Uint8)u_len;
+	return u_len;
+}
+
+#ifdef __KERNEL__
+int udf_get_filename(Uint8 *sname, Uint8 *dname, int flen)
+{
+	struct ustr filename, unifilename;
+	int len;
+
+	if (udf_build_ustr_exact(&unifilename, sname, flen))
+	{
+		return 0;
+	}
+
+	if (!udf_CS0toUTF8(&filename, &unifilename) )
+	{
+		udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
+		return 0;
+	}
+
+	if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
+		unifilename.u_name, unifilename.u_len)))
+	{
+		return len;
+	}
+	return 0;
+}
+#endif
+
+#define ILLEGAL_CHAR_MARK	'_'
+#define EXT_MARK			'.'
+#define CRC_MARK			'#'
+#define EXT_SIZE			5
+
+int udf_translate_to_linux(Uint8 *newName, Uint8 *udfName, int udfLen, Uint8 *fidName, int fidNameLen)
+{
+	int index, newIndex = 0, needsCRC = 0;	
+	int extIndex = 0, newExtIndex = 0, hasExt = 0;
+	unsigned short valueCRC;
+	Uint8 curr;
+	const Uint8 hexChar[] = "0123456789ABCDEF";
+
+	if (udfName[0] == '.' && (udfLen == 1 ||
+		(udfLen == 2 && udfName[1] == '.')))
+	{
+		needsCRC = 1;
+		newIndex = udfLen;
+		memcpy(newName, udfName, udfLen);
+	}
+	else
+	{	
+		for (index = 0; index < udfLen; index++)
+		{
+			curr = udfName[index];
+			if (curr == '/' || curr == 0)
+			{
+				needsCRC = 1;
+				curr = ILLEGAL_CHAR_MARK;
+				while (index+1 < udfLen && (udfName[index+1] == '/' ||
+					udfName[index+1] == 0))
+					index++;
+			}
+			if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
+			{
+				if (udfLen == index + 1)
+					hasExt = 0;
+				else
+				{
+					hasExt = 1;
+					extIndex = index;
+					newExtIndex = newIndex;
+				}
+			}
+			if (newIndex < 256)
+				newName[newIndex++] = curr;
+			else
+				needsCRC = 1;
+		}
+	}
+	if (needsCRC)
+	{
+		Uint8 ext[EXT_SIZE];
+		int localExtIndex = 0;
+
+		if (hasExt)
+		{
+			int maxFilenameLen;
+			for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
+				index++ )
+			{
+				curr = udfName[extIndex + index + 1];
+
+				if (curr == '/' || curr == 0)
+				{
+					needsCRC = 1;
+					curr = ILLEGAL_CHAR_MARK;
+					while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
+						&& (udfName[extIndex + index + 2] == '/' ||
+							udfName[extIndex + index + 2] == 0)))
+						index++;
+				}
+				ext[localExtIndex++] = curr;
+			}
+			maxFilenameLen = 250 - localExtIndex;
+			if (newIndex > maxFilenameLen)
+				newIndex = maxFilenameLen;
+			else
+				newIndex = newExtIndex;
+		}
+		else if (newIndex > 250)
+			newIndex = 250;
+		newName[newIndex++] = CRC_MARK;
+		valueCRC = udf_crc(fidName, fidNameLen, 0);
+		newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
+		newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
+		newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
+		newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
+
+		if (hasExt)
+		{
+			newName[newIndex++] = EXT_MARK;
+			for (index = 0;index < localExtIndex ;index++ )
+				newName[newIndex++] = ext[index];
+		}
+	}
+	return newIndex;
+}
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h
--- v2.3.16/linux/include/asm-alpha/core_cia.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/core_cia.h	Wed Sep  1 15:34:01 1999
@@ -4,7 +4,6 @@
 /* Define to experiment with fitting everything into one 512MB HAE window.  */
 #define CIA_ONE_HAE_WINDOW 1
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_lca.h linux/include/asm-alpha/core_lca.h
--- v2.3.16/linux/include/asm-alpha/core_lca.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/core_lca.h	Wed Sep  1 15:34:01 1999
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_LCA__H__
 #define __ALPHA_LCA__H__
 
-#include <linux/config.h>
 #include <asm/system.h>
 #include <asm/compiler.h>
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h
--- v2.3.16/linux/include/asm-alpha/core_mcpcia.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/core_mcpcia.h	Wed Sep  1 15:34:01 1999
@@ -5,7 +5,6 @@
    One window per bus, that is.  */
 #define MCPCIA_ONE_HAE_WINDOW 1
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <asm/compiler.h>
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_polaris.h linux/include/asm-alpha/core_polaris.h
--- v2.3.16/linux/include/asm-alpha/core_polaris.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/core_polaris.h	Wed Sep  1 15:34:01 1999
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_POLARIS__H__
 #define __ALPHA_POLARIS__H__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_pyxis.h linux/include/asm-alpha/core_pyxis.h
--- v2.3.16/linux/include/asm-alpha/core_pyxis.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/core_pyxis.h	Wed Sep  1 15:34:01 1999
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_PYXIS__H__
 #define __ALPHA_PYXIS__H__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h
--- v2.3.16/linux/include/asm-alpha/core_tsunami.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/core_tsunami.h	Wed Sep  1 15:34:01 1999
@@ -1,7 +1,6 @@
 #ifndef __ALPHA_TSUNAMI__H__
 #define __ALPHA_TSUNAMI__H__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <asm/compiler.h>
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/serial.h linux/include/asm-alpha/serial.h
--- v2.3.16/linux/include/asm-alpha/serial.h	Sat Jul 18 11:30:24 1998
+++ linux/include/asm-alpha/serial.h	Wed Sep  1 14:37:25 1999
@@ -26,6 +26,9 @@
 #define FOURPORT_FLAGS ASYNC_FOURPORT
 #define ACCENT_FLAGS 0
 #define BOCA_FLAGS 0
+#define RS_TABLE_SIZE  64
+#else
+#define RS_TABLE_SIZE  4
 #endif
 	
 #define STD_SERIAL_PORT_DEFNS			\
diff -u --recursive --new-file v2.3.16/linux/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- v2.3.16/linux/include/asm-alpha/smp.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-alpha/smp.h	Wed Sep  1 14:12:09 1999
@@ -19,7 +19,7 @@
 
 #ifdef __SMP__
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 struct cpuinfo_alpha {
 	unsigned long loops_per_sec;
diff -u --recursive --new-file v2.3.16/linux/include/asm-arm/hardirq.h linux/include/asm-arm/hardirq.h
--- v2.3.16/linux/include/asm-arm/hardirq.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-arm/hardirq.h	Wed Sep  1 14:12:09 1999
@@ -1,7 +1,7 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-arm/iomd.h linux/include/asm-arm/iomd.h
--- v2.3.16/linux/include/asm-arm/iomd.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-arm/iomd.h	Wed Sep  1 15:34:01 1999
@@ -1,3 +1,4 @@
+#include <linux/config.h>
 
 #ifndef __ASSEMBLER__
 #define __IOMD(offset)	(IO_IOMD_BASE + (offset >> 2))
diff -u --recursive --new-file v2.3.16/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.3.16/linux/include/asm-i386/bugs.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-i386/bugs.h	Tue Sep  7 11:47:26 1999
@@ -53,7 +53,7 @@
 static void __init copro_timeout(void)
 {
 	fpu_error = 1;
-	timer_table[COPRO_TIMER].expires = jiffies+100;
+	timer_table[COPRO_TIMER].expires = jiffies+HZ;
 	timer_active |= 1<<COPRO_TIMER;
 	printk(KERN_ERR "387 failed: trying to reset\n");
 	send_sig(SIGFPE, current, 1);
diff -u --recursive --new-file v2.3.16/linux/include/asm-i386/desc.h linux/include/asm-i386/desc.h
--- v2.3.16/linux/include/asm-i386/desc.h	Sun Jul 25 23:15:13 1999
+++ linux/include/asm-i386/desc.h	Sat Sep  4 13:06:08 1999
@@ -64,7 +64,7 @@
  * This is the ldt that every process will get unless we need
  * something other than this.
  */
-extern struct desc_struct default_ldt;
+extern struct desc_struct default_ldt[];
 extern void set_intr_gate(unsigned int irq, void * addr);
 extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
 extern void set_tss_desc(unsigned int n, void *addr);
@@ -72,7 +72,7 @@
 extern inline void clear_LDT(void)
 {
 	int cpu = smp_processor_id();
-	set_ldt_desc(cpu, &default_ldt, 1);
+	set_ldt_desc(cpu, &default_ldt[0], 5);
 	__load_LDT(cpu);
 }
 
@@ -86,8 +86,8 @@
 	int count = LDT_ENTRIES;
 
 	if (!segments) {
-		segments = &default_ldt;
-		count = 1;
+		segments = &default_ldt[0];
+		count = 5;
 	}
 		
 	set_ldt_desc(cpu, segments, count);
diff -u --recursive --new-file v2.3.16/linux/include/asm-i386/fixmap.h linux/include/asm-i386/fixmap.h
--- v2.3.16/linux/include/asm-i386/fixmap.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-i386/fixmap.h	Tue Sep  7 11:28:52 1999
@@ -18,7 +18,7 @@
 #include <asm/apic.h>
 #include <asm/page.h>
 #ifdef CONFIG_BIGMEM
-#include <linux/tasks.h>
+#include <linux/threads.h>
 #include <asm/kmap_types.h>
 #endif
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/dvma.h linux/include/asm-m68k/dvma.h
--- v2.3.16/linux/include/asm-m68k/dvma.h	Tue May 11 09:57:14 1999
+++ linux/include/asm-m68k/dvma.h	Sat Sep  4 13:06:41 1999
@@ -9,6 +9,23 @@
 #ifndef __M68K_DVMA_H
 #define __M68K_DVMA_H
 
+#ifdef CONFIG_SUN3
+/* sun3 dvma page support */
+
+/* memory and pmegs reserved for dvma */
+#define DVMA_PMEG_START 10
+#define DVMA_PMEG_END 16
+#define DVMA_START 0xff00000
+#define DVMA_END 0xffe0000
+#define DVMA_SIZE (DVMA_END-DVMA_START)
+
+/* virt <-> phys conversions */
+#define sun3_dvma_vtop(x) ((unsigned long)(x) & 0xffffff)
+#define sun3_dvma_ptov(x) ((unsigned long)(x) | 0xf000000)
+	
+void *sun3_dvma_malloc(int len);
+#else /* Sun3x */
+
 /* Structure to describe the current status of DMA registers on the Sparc */
 struct sparc_dma_registers {
   __volatile__ unsigned long cond_reg;	/* DMA condition register */
@@ -161,5 +178,5 @@
 
 extern unsigned long dvma_alloc (unsigned long, unsigned long);
 extern void dvma_free (unsigned long, unsigned long);
-
+#endif /* !CONFIG_SUN3 */
 #endif /* !(__M68K_DVMA_H) */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/elf.h linux/include/asm-m68k/elf.h
--- v2.3.16/linux/include/asm-m68k/elf.h	Fri Feb  6 10:06:56 1998
+++ linux/include/asm-m68k/elf.h	Sat Sep  4 13:06:41 1999
@@ -33,14 +33,22 @@
 #define ELF_PLAT_INIT(_r)	_r->a1 = 0
 
 #define USE_ELF_CORE_DUMP
+#ifndef CONFIG_SUN3
 #define ELF_EXEC_PAGESIZE	4096
+#else
+#define ELF_EXEC_PAGESIZE	8192
+#endif
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
    use of this is to invoke "./ld.so someprog" to test out a new version of
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
+#ifndef CONFIG_SUN3
 #define ELF_ET_DYN_BASE         0xD0000000UL
+#else
+#define ELF_ET_DYN_BASE         0x0D800000UL
+#endif
 
 #define ELF_CORE_COPY_REGS(pr_reg, regs)				\
 	/* Bleech. */							\
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h
--- v2.3.16/linux/include/asm-m68k/entry.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/entry.h	Sat Sep  4 13:06:41 1999
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <asm/setup.h>
+#include <asm/page.h>
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -132,7 +133,7 @@
 
 .macro	get_current reg=%d0
 	movel	%sp,\reg
-	andw	#-8192,\reg
+	andw	#-KTHREAD_SIZE,\reg
 	movel	\reg,%curptr
 .endm
 
@@ -161,7 +162,7 @@
 #endif
 #define GET_CURRENT(tmp) \
 	"movel	%%sp,"#tmp"\n\t" \
-	"andw	#-8192,"#tmp"\n\t" \
+	"andw	#-KTHREAD_SIZE,"#tmp"\n\t" \
 	"movel	"#tmp",%%a2"
 
 #endif
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/ide.h linux/include/asm-m68k/ide.h
--- v2.3.16/linux/include/asm-m68k/ide.h	Thu May 13 11:00:09 1999
+++ linux/include/asm-m68k/ide.h	Sat Sep  4 13:06:41 1999
@@ -38,6 +38,7 @@
 #include <asm/irq.h>
 
 #ifdef CONFIG_ATARI
+#include <linux/interrupt.h>
 #include <asm/atari_stdma.h>
 #endif
 
@@ -63,7 +64,7 @@
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
 	if (MACH_IS_Q40)
-		return q40ide_default_io_base(index);
+		return (ide_ioreg_t)q40ide_default_io_base(index);
 	else return 0;
 }
 
@@ -82,7 +83,8 @@
 	if (MACH_IS_Q40)
 		return q40_ide_init_hwif_ports(hw, (q40ide_ioreg_t) data_port, (q40ide_ioreg_t) ctrl_port, irq);
 #endif
-	printk("ide_init_hwif_ports: must not be called\n");
+	if (data_port || ctrl_port)
+		printk("ide_init_hwif_ports: must not be called\n");
 }
 
 /*
@@ -104,10 +106,6 @@
 	} b;
 	} select_t;
 
-#ifdef CONFIG_MAC	/* MSch: Hack; wrapper for ide_intr */
-void mac_ide_intr(int irq, void *dev_id, struct pt_regs *regs);
-#endif
-
 static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 			unsigned long flags, const char *device, void *dev_id)
 {
@@ -121,11 +119,7 @@
 #endif /* CONFIG_Q40*/
 #ifdef CONFIG_MAC
 	if (MACH_IS_MAC)
-#if 0	/* MSch Hack: maybe later we'll call ide_intr without a wrapper */
-	return nubus_request_irq(12, dev_id, handler);
-#else
-	return nubus_request_irq(12, dev_id, mac_ide_intr);
-#endif
+		return request_irq(irq, handler, 0, device, dev_id);
 #endif /* CONFIG_MAC */
 	return 0;
 }
@@ -142,7 +136,7 @@
 #endif /* CONFIG_Q40*/
 #ifdef CONFIG_MAC
 	if (MACH_IS_MAC)
-		nubus_free_irq(12);
+		free_irq(irq, dev_id);
 #endif /* CONFIG_MAC */
 }
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/init.h linux/include/asm-m68k/init.h
--- v2.3.16/linux/include/asm-m68k/init.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-m68k/init.h	Sat Sep  4 13:06:41 1999
@@ -12,9 +12,6 @@
 #define __FINIT		.previous
 #define __INITDATA	.section	".data.init",#alloc,#write
 
-#define __cacheline_aligned __attribute__ \
-		((__aligned__(16), __section__ (".data.cacheline_aligned")))
-
 #else
 
 /* gdb doesn't like it all if the code for one source file isn't together in
@@ -26,7 +23,6 @@
 #define __INIT
 #define __FINIT
 #define __INITDATA
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
 
 #endif /* CONFIG_KGDB */
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/intersil.h linux/include/asm-m68k/intersil.h
--- v2.3.16/linux/include/asm-m68k/intersil.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/intersil.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,48 @@
+#ifndef _SUN3_INTERSIL_H
+#define _SUN3_INTERSIL_H
+/* bits 0 and 1 */
+#define INTERSIL_FREQ_32K        0x00
+#define INTERSIL_FREQ_1M         0x01
+#define INTERSIL_FREQ_2M         0x02
+#define INTERSIL_FREQ_4M         0x03
+
+/* bit 2 */
+#define INTERSIL_12H_MODE   0x00
+#define INTERSIL_24H_MODE   0x04
+
+/* bit 3 */
+#define INTESIL_STOP            0x00
+#define INTERSIL_RUN             0x08
+
+/* bit 4 */
+#define INTERSIL_INT_ENABLE     0x10
+#define INTERSIL_INT_DISABLE    0x00
+                
+/* bit 5 */
+#define INTERSIL_MODE_NORMAL     0x00
+#define INTERSIL_MODE_TEST       0x20
+
+#define INTERSIL_HZ_100_MASK	 0x02
+
+struct intersil_dt {
+	u_char	csec;
+	u_char	hour;
+	u_char	minute;
+	u_char	second;
+	u_char	month;
+	u_char	day;
+	u_char	year;
+	u_char	weekday;
+};
+
+struct intersil_7170 {
+	struct intersil_dt counter;
+	struct intersil_dt alarm;
+	u_char	int_reg;
+	u_char	cmd_reg;
+};
+
+extern volatile char* clock_va;
+#define intersil_clock ((volatile struct intersil_7170 *) clock_va)
+#define intersil_clear() (void)intersil_clock->int_reg
+#endif
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/io.h linux/include/asm-m68k/io.h
--- v2.3.16/linux/include/asm-m68k/io.h	Thu May 13 11:00:09 1999
+++ linux/include/asm-m68k/io.h	Sat Sep  4 13:06:41 1999
@@ -14,6 +14,10 @@
 #include <asm/virtconvert.h>
 
 /*
+ * These are for ISA/PCI shared memory _only_ and should never be used
+ * on any other type of memory, including Zorro memory. They are meant to
+ * access the bus in the bus byte order which is little-endian!.
+ *
  * readX/writeX() are used to access memory mapped devices. On some
  * architectures the memory mapped IO stuff needs to be accessed
  * differently. On the m68k architecture, we just read/write the
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_iop.h linux/include/asm-m68k/mac_iop.h
--- v2.3.16/linux/include/asm-m68k/mac_iop.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mac_iop.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,162 @@
+/*
+ * I/O Processor (IOP) defines and structures, mostly snagged from A/UX
+ * header files.
+ *
+ * The original header from which this was taken is copyrighted. I've done some
+ * rewriting (in fact my changes make this a bit more readable, IMHO) but some
+ * more should be done.
+ */
+
+/*
+ * This is the base address of the IOPs. Use this as the address of
+ * a "struct iop" (see below) to see where the actual registers fall.
+ */
+
+#define SCC_IOP_BASE_IIFX	(0x50F04000)
+#define ISM_IOP_BASE_IIFX	(0x50F12000)
+
+#define SCC_IOP_BASE_QUADRA	(0x50F0C000)
+#define ISM_IOP_BASE_QUADRA	(0x50F1E000)
+
+/* IOP status/control register bits: */
+
+#define	IOP_BYPASS	0x01	/* bypass-mode hardware access */
+#define	IOP_AUTOINC	0x02	/* allow autoincrement of ramhi/lo */
+#define	IOP_RUN		0x04	/* set to 0 to reset IOP chip */
+#define	IOP_IRQ		0x08	/* generate IRQ to IOP if 1 */
+#define	IOP_INT0	0x10	/* intr priority from IOP to host */
+#define	IOP_INT1	0x20	/* intr priority from IOP to host */
+#define	IOP_HWINT	0x40	/* IRQ from hardware; bypass mode only */
+#define	IOP_DMAINACTIVE	0x80	/* no DMA request active; bypass mode only */
+
+#define NUM_IOPS	2
+#define NUM_IOP_CHAN	7
+#define NUM_IOP_MSGS	NUM_IOP_CHAN*8
+#define IOP_MSG_LEN	32
+
+/* IOP reference numbers, used by the globally-visible iop_xxx functions */
+
+#define IOP_NUM_SCC	0
+#define IOP_NUM_ISM	1
+
+/* IOP channel states */
+
+#define IOP_MSG_IDLE		0       /* idle                         */
+#define IOP_MSG_NEW		1       /* new message sent             */
+#define IOP_MSG_RCVD		2       /* message received; processing */
+#define IOP_MSG_COMPLETE	3       /* message processing complete  */
+
+/* IOP message status codes */
+
+#define IOP_MSGSTATUS_UNUSED	0	/* Unusued message structure       */
+#define IOP_MSGSTATUS_WAITING	1	/* waiting for channel             */
+#define IOP_MSGSTATUS_SENT	2	/* message sent, awaiting reply    */
+#define IOP_MSGSTATUS_COMPLETE	3	/* message complete and reply rcvd */
+#define IOP_MSGSTATUS_UNSOL	6	/* message is unsolicited          */
+
+/* IOP memory addresses of the members of the the mac_iop_kernel structure. */
+
+#define IOP_ADDR_MAX_SEND_CHAN	0x0200
+#define IOP_ADDR_SEND_STATE	0x0201
+#define IOP_ADDR_PATCH_CTRL	0x021F
+#define IOP_ADDR_SEND_MSG	0x0220
+#define IOP_ADDR_MAX_RECV_CHAN	0x0300
+#define IOP_ADDR_RECV_STATE	0x0301
+#define IOP_ADDR_ALIVE		0x031F
+#define IOP_ADDR_RECV_MSG	0x0320
+
+#ifndef __ASSEMBLY__
+
+/*
+ * IOP Control registers, staggered because in usual Apple style they were
+ * too lazy to decode the A0 bit. This structure is assumed to begin at
+ * one of the xxx_IOP_BASE addresses given above.
+ */
+
+struct mac_iop {
+    __u8	ram_addr_hi;	/* shared RAM address hi byte */
+    __u8	pad0;
+    __u8	ram_addr_lo;	/* shared RAM address lo byte */
+    __u8	pad1;
+    __u8	status_ctrl;	/* status/control register */
+    __u8	pad2[3];
+    __u8	ram_data;	/* RAM data byte at ramhi/lo */
+
+    __u8	pad3[23];
+
+    /* Bypass-mode hardware access registers */
+
+    union {
+	struct {		/* SCC registers */
+	    __u8 sccb_cmd;	/* SCC B command reg */
+	    __u8 pad4;
+	    __u8 scca_cmd;	/* SCC A command reg */
+	    __u8 pad5;
+	    __u8 sccb_data;	/* SCC B data */
+	    __u8 pad6;
+	    __u8 scca_data;	/* SCC A data */
+	} scc_regs;
+
+	struct {		/* ISM registers */
+	    __u8 wdata;		/* write a data byte */
+	    __u8 pad7;
+	    __u8 wmark;		/* write a mark byte */
+	    __u8 pad8;
+	    __u8 wcrc;		/* write 2-byte crc to disk */
+	    __u8 pad9;
+	    __u8 wparams;	/* write the param regs */
+	    __u8 pad10;
+	    __u8 wphase;	/* write the phase states & dirs */
+	    __u8 pad11;
+	    __u8 wsetup;	/* write the setup register */
+	    __u8 pad12;
+	    __u8 wzeroes;	/* mode reg: 1's clr bits, 0's are x */
+	    __u8 pad13;
+	    __u8 wones;		/* mode reg: 1's set bits, 0's are x */
+	    __u8 pad14;
+	    __u8 rdata;		/* read a data byte */
+	    __u8 pad15;
+	    __u8 rmark;		/* read a mark byte */
+	    __u8 pad16;
+	    __u8 rerror;	/* read the error register */
+	    __u8 pad17;
+	    __u8 rparams;	/* read the param regs */
+	    __u8 pad18;
+	    __u8 rphase;	/* read the phase states & dirs */
+	    __u8 pad19;
+	    __u8 rsetup;	/* read the setup register */
+	    __u8 pad20;
+	    __u8 rmode;		/* read the mode register */
+	    __u8 pad21;
+	    __u8 rhandshake;	/* read the handshake register */
+	} ism_regs;
+    } b;
+};
+
+/* This structure is used to track IOP messages in the Linux kernel */
+
+struct iop_msg {
+	struct iop_msg	*next;		/* next message in queue or NULL     */
+	uint	iop_num;		/* IOP number                        */
+	uint	channel;		/* channel number                    */
+	void	*caller_priv;		/* caller private data               */
+	int	status;			/* status of this message            */
+	__u8	message[IOP_MSG_LEN];	/* the message being sent/received   */
+	__u8	reply[IOP_MSG_LEN];	/* the reply to the message          */
+	void	(*handler)(struct iop_msg *, struct pt_regs *);
+					/* function to call when reply recvd */
+};
+
+extern int iop_scc_present,iop_ism_present;
+
+extern int iop_listen(uint, uint,
+			void (*handler)(struct iop_msg *, struct pt_regs *),
+			const char *);
+extern int iop_send_message(uint, uint, void *, uint, __u8 *,
+			    void (*)(struct iop_msg *, struct pt_regs *));
+extern void iop_complete_message(struct iop_msg *);
+extern void iop_upload_code(uint, __u8 *, uint, __u16);
+extern void iop_download_code(uint, __u8 *, uint, __u16);
+extern __u8 *iop_compare_code(uint, __u8 *, uint, __u16);
+
+#endif /* __ASSEMBLY__ */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_oss.h linux/include/asm-m68k/mac_oss.h
--- v2.3.16/linux/include/asm-m68k/mac_oss.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mac_oss.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,94 @@
+/*
+ *	OSS
+ *
+ *	This is used in place of VIA2 on the IIfx.
+ */
+ 
+#define OSS_BASE	(0x50f1a000)
+
+/*
+ * Interrupt level offsets for mac_oss->irq_level
+ */
+
+#define OSS_NUBUS0	0
+#define OSS_NUBUS1	1
+#define OSS_NUBUS2	2
+#define OSS_NUBUS3	3
+#define OSS_NUBUS4	4
+#define OSS_NUBUS5	5
+#define OSS_IOPISM	6
+#define OSS_IOPSCC	7
+#define OSS_SOUND	8
+#define OSS_SCSI	9
+#define OSS_60HZ	10
+#define OSS_VIA1	11
+#define OSS_UNUSED1	12
+#define OSS_UNUSED2	13
+#define OSS_PARITY	14
+#define OSS_UNUSED3	15
+
+#define OSS_NUM_SOURCES	16
+
+/*
+ * Pending interrupt bits in mac_oss->irq_pending
+ */
+
+#define OSS_IP_NUBUS0	0x0001
+#define OSS_IP_NUBUS1	0x0002
+#define OSS_IP_NUBUS2	0x0004
+#define OSS_IP_NUBUS3	0x0008
+#define OSS_IP_NUBUS4	0x0010
+#define OSS_IP_NUBUS5	0x0020
+#define OSS_IP_IOPISM	0x0040
+#define OSS_IP_IOPSCC	0x0080
+#define OSS_IP_SOUND	0x0100
+#define OSS_IP_SCSI	0x0200
+#define OSS_IP_60HZ	0x0400
+#define OSS_IP_VIA1	0x0800
+#define OSS_IP_UNUSED1	0x1000
+#define OSS_IP_UNUSED2	0x2000
+#define OSS_IP_PARITY	0x4000
+#define OSS_IP_UNUSED3	0x8000
+
+#define OSS_IP_NUBUS (OSS_IP_NUBUS0|OSS_IP_NUBUS1|OSS_IP_NUBUS2|OSS_IP_NUBUS3|OSS_IP_NUBUS4|OSS_IP_NUBUS5)
+
+/*
+ * Rom Control Register
+ */
+
+#define OSS_POWEROFF	0x80
+
+/*
+ * OSS Interrupt levels for various sub-systems
+ *
+ * This mapping is layed out with two things in mind: first, we try to keep
+ * things on their own levels to avoid having to do double-dispatches. Second,
+ * the levels match as closely as possible the alternate IRQ mapping mode (aka
+ * "A/UX mode") available on some VIA machines.
+ */
+
+#define OSS_IRQLEV_DISABLED	0
+#define OSS_IRQLEV_IOPISM	1	/* ADB? */
+#define OSS_IRQLEV_SCSI		2
+#define OSS_IRQLEV_NUBUS	3	/* keep this on its own level */
+#define OSS_IRQLEV_IOPSCC	4	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_SOUND	5	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_60HZ		6	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_VIA1		6	/* matches VIA alternate mapping */
+#define OSS_IRQLEV_PARITY	7	/* matches VIA alternate mapping */
+
+#ifndef __ASSEMBLY__
+
+struct mac_oss {
+    __u8  irq_level[0x10];	/* [0x000-0x00f] Interrupt levels */
+    __u8  padding0[0x1F2];	/* [0x010-0x201] IO space filler */
+    __u16 irq_pending;		/* [0x202-0x203] pending interrupts bits */
+    __u8  rom_ctrl;		/* [0x204-0x204] ROM cntl reg (for poweroff) */
+    __u8  padding1[0x2];	/* [0x205-0x206] currently unused by A/UX */
+    __u8  ack_60hz;		/* [0x207-0x207] 60 Hz ack. */
+};
+
+extern volatile struct mac_oss *oss;
+extern int oss_present;
+
+#endif /* __ASSEMBLY__ */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_psc.h linux/include/asm-m68k/mac_psc.h
--- v2.3.16/linux/include/asm-m68k/mac_psc.h	Mon Oct  5 13:54:39 1998
+++ linux/include/asm-m68k/mac_psc.h	Sat Sep  4 13:06:41 1999
@@ -1,73 +1,243 @@
 /*
- *	Apple Peripheral System Controller (PSC)
+ * Apple Peripheral System Controller (PSC)
  *
- *	The PSC is used on the AV Macs to control IO functions not handled
- *	by the VIAs (Ethernet, DSP, SCC).
+ * The PSC is used on the AV Macs to control IO functions not handled
+ * by the VIAs (Ethernet, DSP, SCC, Sound). This includes nine DMA
+ * channels.
+ *
+ * The first seven DMA channels appear to be "one-shot" and are actually
+ * sets of two channels; one member is active while the other is being
+ * configured, and then you flip the active member and start all over again.
+ * The one-shot channels are grouped together and are:
+ *
+ * 1. SCSI
+ * 2. Ethernet Read
+ * 3. Ethernet Write
+ * 4. Floppy Disk Controller
+ * 5. SCC Channel A Receive
+ * 6. SCC Channel B Receive
+ * 7. SCC Channel A Transmit
+ *
+ * The remaining two channels are handled somewhat differently. They appear
+ * to be closely tied and share one set of registers. They also seem to run
+ * continuously, although how you keep the buffer filled in this scenario is
+ * not understood as there seems to be only one input and one output buffer
+ * pointer.
+ * 
+ * Much of this was extrapolated from what was known about the Ethernet
+ * registers and subsequently confirmed using MacsBug (ie by pinging the
+ * machine with easy-to-find patterns and looking for them in the DMA
+ * buffers, or by sending a file over the serial ports and finding the
+ * file in the buffers.)
+ *
+ * 1999-05-25 (jmt)
  */
- 
-#define PSCBASE		0x50F31000
+
+#define PSC_BASE	(0x50F31000)
 
 /*
- *	The IER/IFR registers work like the VIA, except that it has 4
- *	of them each on different interrupt levels.
+ * The IER/IFR registers work like the VIA, except that it has 4
+ * of them each on different interrupt levels, and each register
+ * set only seems to handle four interrupts instead of seven.
+ *
+ * To access a particular set of registers, add 0xn0 to the base
+ * where n = 3,4,5 or 6.
  */
  
-#define pIFR3		0x130
-#define pIFR4		0x140
-#define pIFR5		0x150
-#define pIFR6		0x160
-
-#define pIER3		0x134
-#define pIER4		0x144
-#define pIER5		0x154
-#define pIER6		0x164
+#define pIFRbase	0x100
+#define pIERbase	0x104
 
 /*
- *	Ethernet Control Registers
+ * One-shot DMA control registers
  */
- 
-#define PSC_ENETRD_CTL  0xc10
-#define PSC_ENETWR_CTL  0xc20
+
+#define PSC_CTL_BASE	0xC00
+
+#define PSC_SCSI_CTL	0xC00
+#define PSC_ENETRD_CTL  0xC10
+#define PSC_ENETWR_CTL  0xC20
+#define PSC_FDC_CTL	0xC30
+#define PSC_SCCA_CTL	0xC40
+#define PSC_SCCB_CTL	0xC50
+#define PSC_SCCATX_CTL	0xC60
+
+/*
+ * DMA channels. Add +0x10 for the second channel in the set.
+ * You're supposed to use one channel while the other runs and
+ * then flip channels and do the whole thing again.
+ */
+
+#define PSC_ADDR_BASE	0x1000
+#define PSC_LEN_BASE	0x1004
+#define PSC_CMD_BASE	0x1008
+
+#define PSC_SCSI_ADDR	0x1000 	/* confirmed */
+#define PSC_SCSI_LEN	0x1004 	/* confirmed */
+#define PSC_SCSI_CMD	0x1008 	/* confirmed */
+#define PSC_ENETRD_ADDR 0x1020	/* confirmed */
+#define PSC_ENETRD_LEN  0x1024	/* confirmed */
+#define PSC_ENETRD_CMD  0x1028	/* confirmed */
+#define PSC_ENETWR_ADDR 0x1040	/* confirmed */
+#define PSC_ENETWR_LEN  0x1044	/* confirmed */
+#define PSC_ENETWR_CMD  0x1048	/* confirmed */
+#define PSC_FDC_ADDR	0x1060	/* strongly suspected */
+#define PSC_FDC_LEN	0x1064	/* strongly suspected */
+#define PSC_FDC_CMD	0x1068	/* strongly suspected */
+#define PSC_SCCA_ADDR	0x1080	/* confirmed */
+#define PSC_SCCA_LEN	0x1084	/* confirmed */
+#define PSC_SCCA_CMD	0x1088	/* confirmed */
+#define PSC_SCCB_ADDR	0x10A0	/* confirmed */
+#define PSC_SCCB_LEN	0x10A4	/* confirmed */
+#define PSC_SCCB_CMD	0x10A8	/* confirmed */
+#define PSC_SCCATX_ADDR	0x10C0	/* confirmed */
+#define PSC_SCCATX_LEN	0x10C4	/* confirmed */
+#define PSC_SCCATX_CMD	0x10C8	/* confirmed */
 
 /*
- *	Receive DMA channel (add +0x10 for 2nd channel)
+ * Free-running DMA registers. The only part known for sure are the bits in
+ * the control register, the buffer addresses and the buffer length. Everything
+ * else is anybody's guess.
+ *
+ * These registers seem to be mirrored every thirty-two bytes up until offset
+ * 0x300. It's safe to assume then that a new set of registers starts there.
  */
- 
-#define PSC_ENETRD_ADDR 0x1020 
-#define PSC_ENETRD_LEN  0x1024
-#define PSC_ENETRD_CMD  0x1028
+
+#define PSC_SND_CTL	0x200	/*
+				 * [ 16-bit ]
+				 * Sound (Singer?) control register.
+				 *
+				 * bit 0  : ????
+				 * bit 1  : ????
+				 * bit 2  : Set to one to enable sound
+				 *          output. Possibly a mute flag.
+				 * bit 3  : ????
+				 * bit 4  : ????
+				 * bit 5  : ????
+				 * bit 6  : Set to one to enable pass-thru
+				 *          audio. In this mode the audio data
+				 *          seems to appear in both the input
+				 *          buffer and the output buffer.
+				 * bit 7  : Set to one to activate the
+				 *          sound input DMA or zero to
+				 *          disable it.
+				 * bit 8  : Set to one to activate the
+				 *          sound output DMA or zero to
+				 *          disable it.
+				 * bit 9  : \
+				 * bit 11 :  |
+				 *          These two bits control the sample
+				 *          rate. Usually set to binary 10 and
+				 *	    MacOS 8.0 says I'm at 48 KHz. Using
+				 *	    a binary value of 01 makes things
+				 *	    sound about 1/2 speed (24 KHz?) and
+				 *          binary 00 is slower still (22 KHz?)
+				 *
+				 * Setting this to 0x0000 is a good way to
+				 * kill all DMA at boot time so that the
+				 * PSC won't overwrite the kernel image
+				 * with sound data.
+				 */
 
 /*
- *	Transmit DMA channel (add +0x10 for 2nd channel)
+ * 0x0202 - 0x0203 is unused. Writing there
+ * seems to clobber the control register.
  */
- 
-#define PSC_ENETWR_ADDR 0x1040
-#define PSC_ENETWR_LEN  0x1044
-#define PSC_ENETWR_CMD  0x1048
+
+#define PSC_SND_SOURCE	0x204	/*
+				 * [ 32-bit ]
+				 * Controls input source and volume:
+				 *
+				 * bits 12-15 : input source volume, 0 - F
+				 * bits 16-19 : unknown, always 0x5
+				 * bits 20-23 : input source selection:
+				 *                  0x3 = CD Audio
+				 *                  0x4 = External Audio
+				 *
+				 * The volume is definately not the general
+				 * output volume as it doesn't affect the
+				 * alert sound volume.
+				 */
+#define PSC_SND_STATUS1	0x208	/*
+				 * [ 32-bit ]
+				 * Appears to be a read-only status register.
+				 * The usual value is 0x00400002.
+				 */
+#define PSC_SND_HUH3	0x20C	/*
+				 * [ 16-bit ]
+				 * Unknown 16-bit value, always 0x0000.
+				 */
+#define PSC_SND_BITS2GO	0x20E	/*
+				 * [ 16-bit ]
+				 * Counts down to zero from some constant
+				 * value. The value appears to be the
+				 * number of _bits_ remaining before the
+				 * buffer is full, which would make sense
+				 * since Apple's docs say the sound DMA
+				 * channels are 1 bit wide.
+				 */
+#define PSC_SND_INADDR	0x210	/*
+				 * [ 32-bit ]
+				 * Address of the sound input DMA buffer
+				 */
+#define PSC_SND_OUTADDR	0x214	/*
+				 * [ 32-bit ]
+				 * Address of the sound output DMA buffer
+				 */
+#define PSC_SND_LEN	0x218	/*
+				 * [ 16-bit ]
+				 * Length of both buffers in eight-byte units.
+				 */
+#define PSC_SND_HUH4	0x21A	/*
+				 * [ 16-bit ]
+				 * Unknown, always 0x0000.
+				 */
+#define PSC_SND_STATUS2	0x21C	/*
+				 * [ 16-bit ]
+				 * Appears to e a read-only status register.
+				 * The usual value is 0x0200.
+				 */
+#define PSC_SND_HUH5	0x21E	/*
+				 * [ 16-bit ]
+				 * Unknown, always 0x0000.
+				 */
+
+#ifndef __ASSEMBLY__
+
+extern volatile __u8 *psc;
+extern int psc_present;
 
 /*
  *	Access functions
  */
  
-extern volatile unsigned char *psc;
+extern inline void psc_write_byte(int offset, __u8 data)
+{
+	*((volatile __u8 *)(psc + offset)) = data;
+}
+
+extern inline void psc_write_word(int offset, __u16 data)
+{
+	*((volatile __u16 *)(psc + offset)) = data;
+}
 
-extern inline void psc_write_word(int offset, u16 data)
+extern inline void psc_write_long(int offset, __u32 data)
 {
-	*((volatile u16 *)(psc+offset)) = data;
+	*((volatile __u32 *)(psc + offset)) = data;
 }
 
-extern inline void psc_write_long(int offset, u32 data)
+extern inline u8 psc_read_byte(int offset)
 {
-	*((volatile u32 *)(psc+offset)) = data;
+	return *((volatile __u8 *)(psc + offset));
 }
 
 extern inline u16 psc_read_word(int offset)
 {
-	return *((volatile u16 *)(psc+offset));
+	return *((volatile __u16 *)(psc + offset));
 }
 
 extern inline u32 psc_read_long(int offset)
 {
-	return *((volatile u32 *)(psc+offset));
+	return *((volatile __u32 *)(psc + offset));
 }
 
+#endif /* __ASSEMBLY__ */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mac_via.h linux/include/asm-m68k/mac_via.h
--- v2.3.16/linux/include/asm-m68k/mac_via.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/mac_via.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,267 @@
+/*
+ *	6522 Versatile Interface Adapter (VIA)
+ *
+ *	There are two of these on the Mac II. Some IRQ's are vectored
+ *	via them as are assorted bits and bobs - eg rtc, adb. The picture
+ *	is a bit incomplete as the Mac documentation doesnt cover this well
+ */
+ 
+#ifndef _ASM_MAC_VIA_H_
+#define _ASM_MAC_VIA_H_
+
+/*
+ * Base addresses for the VIAs. There are two in every machine,
+ * although on some machines the second is an RBV or an OSS.
+ * The OSS is different enough that it's handled separately.
+ *
+ * Do not use these values directly; use the via1 and via2 variables
+ * instead (and don't forget to check rbv_present when using via2!)
+ */
+
+#define VIA1_BASE	(0x50F00000)
+#define VIA2_BASE	(0x50F02000)
+#define  RBV_BASE	(0x50F26000)
+ 
+/*
+ *	Not all of these are true post MacII I think.
+ *      CSA: probably the ones CHRP marks as 'unused' change purposes
+ *      when the IWM becomes the SWIM.
+ *      http://www.rs6000.ibm.com/resource/technology/chrpio/via5.mak.html
+ *      ftp://ftp.austin.ibm.com/pub/technology/spec/chrp/inwork/CHRP_IORef_1.0.pdf
+ *
+ * also, http://developer.apple.com/technotes/hw/hw_09.html claims the
+ * following changes for IIfx:
+ * VIA1A_vSccWrReq not available and that VIA1A_vSync has moved to an IOP.
+ * Also, "All of the functionality of VIA2 has been moved to other chips".
+ */
+ 
+#define VIA1A_vSccWrReq	0x80	/* SCC write. (input)
+				 * [CHRP] SCC WREQ: Reflects the state of the 
+				 * Wait/Request pins from the SCC.
+				 * [Macintosh Family Hardware]
+				 * as CHRP on SE/30,II,IIx,IIcx,IIci.
+				 * on IIfx, "0 means an active request"
+				 */
+#define VIA1A_vRev8	0x40	/* Revision 8 board ???
+                                 * [CHRP] En WaitReqB: Lets the WaitReq_L
+				 * signal from port B of the SCC appear on
+				 * the PA7 input pin. Output.
+				 * [Macintosh Family] On the SE/30, this
+				 * is the bit to flip screen buffers.
+				 * 0=alternate, 1=main.
+				 * on II,IIx,IIcx,IIci,IIfx this is a bit
+				 * for Rev ID. 0=II,IIx, 1=IIcx,IIci,IIfx
+				 */
+#define VIA1A_vHeadSel	0x20	/* Head select for IWM.
+				 * [CHRP] unused.
+				 * [Macintosh Family] "Floppy disk
+				 * state-control line SEL" on all but IIfx
+				 */
+#define VIA1A_vOverlay	0x10    /* [Macintosh Family] On SE/30,II,IIx,IIcx
+				 * this bit enables the "Overlay" address
+				 * map in the address decoders as it is on
+				 * reset for mapping the ROM over the reset
+				 * vector. 1=use overlay map.
+				 * On the IIci,IIfx it is another bit of the
+				 * CPU ID: 0=normal IIci, 1=IIci with parity
+				 * feature or IIfx.
+				 * [CHRP] En WaitReqA: Lets the WaitReq_L
+				 * signal from port A of the SCC appear
+				 * on the PA7 input pin (CHRP). Output.
+				 * [MkLinux] "Drive Select"
+				 *  (with 0x20 being 'disk head select')
+				 */
+#define VIA1A_vSync	0x08    /* [CHRP] Sync Modem: modem clock select:
+                                 * 1: select the external serial clock to
+				 *    drive the SCC's /RTxCA pin.
+				 * 0: Select the 3.6864MHz clock to drive
+				 *    the SCC cell.
+				 * [Macintosh Family] Correct on all but IIfx
+				 */
+
+/* Macintosh Family Hardware sez: bits 0-2 of VIA1A are volume control
+ * on Macs which had the PWM sound hardware.  Reserved on newer models.
+ * On IIci,IIfx, bits 1-2 are the rest of the CPU ID:
+ * bit 2: 1=IIci, 0=IIfx
+ * bit 1: 1 on both IIci and IIfx.
+ * MkLinux sez bit 0 is 'burnin flag' in this case.
+ * CHRP sez: VIA1A bits 0-2 and 5 are 'unused': if programmed as
+ * inputs, these bits will read 0.
+ */
+#define VIA1A_vVolume	0x07	/* Audio volume mask for PWM */
+#define VIA1A_CPUID0	0x02	/* CPU id bit 0 on RBV, others */
+#define VIA1A_CPUID1	0x04	/* CPU id bit 0 on RBV, others */
+#define VIA1A_CPUID2	0x10	/* CPU id bit 0 on RBV, others */
+#define VIA1A_CPUID3	0x40	/* CPU id bit 0 on RBV, others */
+ 	
+/* Info on VIA1B is from Macintosh Family Hardware & MkLinux.
+ * CHRP offers no info. */
+#define VIA1B_vSound	0x80	/* Sound enable (for compatibility with
+				 * PWM hardware) 0=enabled.
+				 * Also, on IIci w/parity, shows parity error
+				 * 0=error, 1=OK. */
+#define VIA1B_vMystery	0x40    /* On IIci, parity enable. 0=enabled,1=disabled
+				 * On SE/30, vertical sync interrupt enable.
+				 * 0=enabled. This vSync interrupt shows up
+				 * as a slot $E interrupt. */
+#define VIA1B_vADBS2	0x20	/* ADB state input bit 1 (unused on IIfx) */
+#define VIA1B_vADBS1	0x10	/* ADB state input bit 0 (unused on IIfx) */
+#define VIA1B_vADBInt	0x08	/* ADB interrupt 0=interrupt (unused on IIfx)*/
+#define VIA1B_vRTCEnb	0x04	/* Enable Real time clock. 0=enabled. */
+#define VIA1B_vRTCClk	0x02    /* Real time clock serial-clock line. */
+#define VIA1B_vRTCData	0x01    /* Real time clock serial-data line. */
+
+/* MkLinux defines the following "VIA1 Register B contents where they
+ * differ from standard VIA1".  From the naming scheme, we assume they
+ * correspond to a VIA work-alike named 'EVR'. */
+#define	EVRB_XCVR	0x08	/* XCVR_SESSION* */
+#define	EVRB_FULL	0x10	/* VIA_FULL */
+#define	EVRB_SYSES	0x20	/* SYS_SESSION */
+#define	EVRB_AUXIE	0x00	/* Enable A/UX Interrupt Scheme */
+#define	EVRB_AUXID	0x40	/* Disable A/UX Interrupt Scheme */
+#define	EVRB_SFTWRIE	0x00	/* Software Interrupt ReQuest */
+#define	EVRB_SFTWRID	0x80	/* Software Interrupt ReQuest */
+
+/*
+ *	VIA2 A register is the interrupt lines raised off the nubus 
+ *	slots.
+ *      The below info is from 'Macintosh Family Hardware.'
+ *      MkLinux calls the 'IIci internal video IRQ' below the 'RBV slot 0 irq.'
+ *      It also notes that the slot $9 IRQ is the 'Ethernet IRQ' and
+ *      defines the 'Video IRQ' as 0x40 for the 'EVR' VIA work-alike.
+ *      Perhaps OSS uses vRAM1 and vRAM2 for ADB.
+ */
+ 
+#define VIA2A_vRAM1	0x80	/* RAM size bit 1 (IIci: reserved) */
+#define VIA2A_vRAM0	0x40	/* RAM size bit 0 (IIci: internal video IRQ) */
+#define VIA2A_vIRQE	0x20	/* IRQ from slot $E */
+#define VIA2A_vIRQD	0x10	/* IRQ from slot $D */
+#define VIA2A_vIRQC	0x08	/* IRQ from slot $C */
+#define VIA2A_vIRQB	0x04	/* IRQ from slot $B */
+#define VIA2A_vIRQA	0x02	/* IRQ from slot $A */
+#define VIA2A_vIRQ9	0x01	/* IRQ from slot $9 */
+
+/* RAM size bits decoded as follows:
+ * bit1 bit0  size of ICs in bank A
+ *  0    0    256 kbit
+ *  0    1    1 Mbit
+ *  1    0    4 Mbit
+ *  1    1   16 Mbit
+ */
+ 
+/*
+ *	Register B has the fun stuff in it
+ */
+ 
+#define VIA2B_vVBL	0x80	/* VBL output to VIA1 (60.15Hz) driven by
+				 * timer T1.
+				 * on IIci, parity test: 0=test mode.
+				 * [MkLinux] RBV_PARODD: 1=odd,0=even. */
+#define VIA2B_vSndJck	0x40	/* External sound jack status.
+				 * 0=plug is inserted.  On SE/30, always 0 */
+#define VIA2B_vTfr0	0x20	/* Transfer mode bit 0 ack from NuBus */
+#define VIA2B_vTfr1	0x10	/* Transfer mode bit 1 ack from NuBus */
+#define VIA2B_vMode32	0x08	/* 24/32bit switch - doubles as cache flush
+				 * on II, AMU/PMMU control.
+				 *   if AMU, 0=24bit to 32bit translation
+				 *   if PMMU, 1=PMMU is accessing page table.
+				 * on SE/30 tied low.
+				 * on IIx,IIcx,IIfx, unused.
+				 * on IIci/RBV, cache control. 0=flush cache.
+				 */
+#define VIA2B_vPower	0x04	/* Power off, 0=shut off power.
+				 * on SE/30 this signal sent to PDS card. */
+#define VIA2B_vBusLk	0x02	/* Lock NuBus transactions, 0=locked.
+				 * on SE/30 sent to PDS card. */
+#define VIA2B_vCDis	0x01	/* Cache control. On IIci, 1=disable cache card
+				 * on others, 0=disable processor's instruction
+				 * and data caches. */
+
+/* Apple sez: http://developer.apple.com/technotes/ov/ov_04.html
+ * Another example of a valid function that has no ROM support is the use
+ * of the alternate video page for page-flipping animation. Since there
+ * is no ROM call to flip pages, it is necessary to go play with the
+ * right bit in the VIA chip (6522 Versatile Interface Adapter).
+ * [CSA: don't know which one this is, but it's one of 'em!]
+ */
+ 
+/*
+ *	6522 registers - see databook.
+ * CSA: Assignments for VIA1 confirmed from CHRP spec.
+ */ 
+
+/* partial address decode.  0xYYXX : XX part for RBV, YY part for VIA */
+/* Note: 15 VIA regs, 8 RBV regs */
+
+#define vBufB	0x0000	/* [VIA/RBV]  Register B */
+#define vBufAH	0x0200  /* [VIA only] Buffer A, with handshake. DON'T USE! */
+#define vDirB	0x0400  /* [VIA only] Data Direction Register B. */
+#define vDirA	0x0600  /* [VIA only] Data Direction Register A. */
+#define vT1CL	0x0800  /* [VIA only] Timer one counter low. */
+#define vT1CH	0x0a00  /* [VIA only] Timer one counter high. */
+#define vT1LL	0x0c00  /* [VIA only] Timer one latches low. */
+#define vT1LH	0x0e00  /* [VIA only] Timer one latches high. */
+#define vT2CL	0x1000  /* [VIA only] Timer two counter low. */
+#define vT2CH	0x1200  /* [VIA only] Timer two counter high. */
+#define vSR	0x1400  /* [VIA only] Shift register. */
+#define vACR	0x1600  /* [VIA only] Auxilary control register. */
+#define vPCR	0x1800  /* [VIA only] Peripheral control register. */
+                        /*            CHRP sez never ever to *write* this.
+			 *            Mac family says never to *change* this.
+			 * In fact we need to initialize it once at start. */
+#define vIFR	0x1a00  /* [VIA/RBV]  Interrupt flag register. */
+#define vIER	0x1c00  /* [VIA/RBV]  Interrupt enable register. */
+#define vBufA	0x1e00  /* [VIA/RBV] register A (no handshake) */
+
+/* The RBV only decodes the bottom eight address lines; the VIA doesn't
+ * decode the bottom eight -- so vBufB | rBufB will always get you BufB */
+/* CSA: in fact, only bits 0,1, and 4 seem to be decoded.
+ * BUT note the values for rIER and rIFR, where the top 8 bits *do* seem
+ * to matter.  In fact *all* of the top 8 bits seem to matter; 
+ * setting rIER=0x1813 and rIFR=0x1803 doesn't work, either.
+ * Perhaps some sort of 'compatibility mode' is built-in? [21-May-1999]
+ */
+
+#define rBufB   0x0000  /* [VIA/RBV]  Register B */
+#define rExp	0x0001	/* [RBV only] RBV future expansion (always 0) */
+#define rSIFR	0x0002  /* [RBV only] RBV slot interrupts register. */
+#define rIFR	0x1a03  /* [VIA/RBV]  RBV interrupt flag register. */
+#define rMonP   0x0010  /* [RBV only] RBV video monitor type. */
+#define rChpT   0x0011  /* [RBV only] RBV test mode register (reads as 0). */
+#define rSIER   0x0012  /* [RBV only] RBV slot interrupt enables. */
+#define rIER    0x1c13  /* [VIA/RBV]  RBV interrupt flag enable register. */
+#define rBufA	rSIFR   /* the 'slot interrupts register' is BufA on a VIA */
+
+/*
+ * Video monitor parameters, for rMonP:
+ */
+#define RBV_DEPTH  0x07	/* bits per pixel: 000=1,001=2,010=4,011=8 */
+#define RBV_MONID  0x38	/* monitor type, as below. */
+#define RBV_VIDOFF 0x40	/* 1 turns off onboard video */
+/* Supported monitor types: */
+#define MON_15BW   (1<<3) /* 15" BW portrait. */
+#define MON_IIGS   (2<<3) /* 12" color (modified IIGS monitor). */
+#define MON_15RGB  (5<<3) /* 15" RGB portrait. */
+#define MON_12OR13 (6<<3) /* 12" BW or 13" RGB. */
+#define MON_NONE   (7<<3) /* No monitor attached. */
+
+/* To clarify IER manipulations */
+#define IER_SET_BIT(b) (0x80 | (1<<(b)) )
+#define IER_CLR_BIT(b) (0x7F & (1<<(b)) )
+
+#ifndef __ASSEMBLY__
+
+extern volatile __u8 *via1,*via2;
+extern int rbv_present,via_alt_mapping;
+extern __u8 rbv_clear;
+
+extern __inline__ int rbv_set_video_bpp(int bpp) {
+	char val = (bpp==1)?0:(bpp==2)?1:(bpp==4)?2:(bpp==8)?3:-1;
+	if (!rbv_present || val<0) return -1;
+	via2[rMonP] = (via2[rMonP] & ~RBV_DEPTH) | val;
+	return 0;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_MAC_VIA_H_ */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h
--- v2.3.16/linux/include/asm-m68k/machdep.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/machdep.h	Sat Sep  4 13:06:41 1999
@@ -30,6 +30,8 @@
 extern int (*mach_hwclk)(int, struct hwclk_time*);
 extern int (*mach_set_clock_mmss)(unsigned long);
 extern void (*mach_reset)( void );
+extern void (*mach_halt)( void );
+extern void (*mach_power_off)( void );
 extern unsigned long (*mach_hd_init) (unsigned long, unsigned long);
 extern void (*mach_hd_setup)(char *, int *);
 extern long mach_max_dma_address;
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/machines.h linux/include/asm-m68k/machines.h
--- v2.3.16/linux/include/asm-m68k/machines.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/machines.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,87 @@
+/* $Id: machines.h,v 1.4 1995/11/25 02:31:58 davem Exp $
+ * machines.h:  Defines for taking apart the machine type value in the
+ *              idprom and determining the kind of machine we are on.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au)
+ */
+#ifndef _SPARC_MACHINES_H
+#define _SPARC_MACHINES_H
+
+struct Sun_Machine_Models {
+	char *name;
+	unsigned char id_machtype;
+};
+
+/* Current number of machines we know about that has an IDPROM
+ * machtype entry including one entry for the 0x80 OBP machines.
+ */
+// reduced along with table in arch/m68k/sun3/idprom.c
+// sun3 port doesn't need to know about sparc machines.
+//#define NUM_SUN_MACHINES   23
+#define NUM_SUN_MACHINES  8
+
+extern struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES];
+
+/* The machine type in the idprom area looks like this:
+ *
+ * ---------------
+ * | ARCH | MACH |
+ * ---------------
+ *  7    4 3    0
+ *
+ * The ARCH field determines the architecture line (sun4, sun4c, etc).
+ * The MACH field determines the machine make within that architecture.
+ */
+
+#define SM_ARCH_MASK  0xf0
+#define SM_SUN3       0x10
+#define SM_SUN4       0x20
+#define SM_SUN3X      0x40
+#define SM_SUN4C      0x50
+#define SM_SUN4M      0x70
+#define SM_SUN4M_OBP  0x80
+
+#define SM_TYP_MASK   0x0f
+/* Sun3 machines */
+#define SM_3_160      0x01    /* Sun 3/160 series */
+#define SM_3_50       0x02    /* Sun 3/50 series */
+#define SM_3_260      0x03    /* Sun 3/260 series */
+#define SM_3_110      0x04    /* Sun 3/110 series */
+#define SM_3_60       0x07    /* Sun 3/60 series */
+#define SM_3_E        0x08    /* Sun 3/E series */
+
+/* Sun3x machines */
+#define SM_3_460      0x01    /* Sun 3/460 (460,470,480) series */
+#define SM_3_80       0x02    /* Sun 3/80 series */
+
+/* Sun4 machines */
+#define SM_4_260      0x01    /* Sun 4/200 series */
+#define SM_4_110      0x02    /* Sun 4/100 series */
+#define SM_4_330      0x03    /* Sun 4/300 series */
+#define SM_4_470      0x04    /* Sun 4/400 series */
+
+/* Sun4c machines                Full Name              - PROM NAME */
+#define SM_4C_SS1     0x01    /* Sun4c SparcStation 1   - Sun 4/60  */
+#define SM_4C_IPC     0x02    /* Sun4c SparcStation IPC - Sun 4/40  */
+#define SM_4C_SS1PLUS 0x03    /* Sun4c SparcStation 1+  - Sun 4/65  */
+#define SM_4C_SLC     0x04    /* Sun4c SparcStation SLC - Sun 4/20  */
+#define SM_4C_SS2     0x05    /* Sun4c SparcStation 2   - Sun 4/75  */
+#define SM_4C_ELC     0x06    /* Sun4c SparcStation ELC - Sun 4/25  */
+#define SM_4C_IPX     0x07    /* Sun4c SparcStation IPX - Sun 4/50  */
+
+/* Sun4m machines, these predate the OpenBoot.  These values only mean
+ * something if the value in the ARCH field is SM_SUN4M, if it is
+ * SM_SUN4M_OBP then you have the following situation:
+ * 1) You either have a sun4d, a sun4e, or a recently made sun4m.
+ * 2) You have to consult OpenBoot to determine which machine this is.
+ */
+#define SM_4M_SS60    0x01    /* Sun4m SparcSystem 600                  */
+#define SM_4M_SS50    0x02    /* Sun4m SparcStation 10                  */
+#define SM_4M_SS40    0x03    /* Sun4m SparcStation 5                   */
+
+/* Sun4d machines -- N/A */
+/* Sun4e machines -- N/A */
+/* Sun4u machines -- N/A */
+
+#endif /* !(_SPARC_MACHINES_H) */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/machw.h linux/include/asm-m68k/machw.h
--- v2.3.16/linux/include/asm-m68k/machw.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/machw.h	Sat Sep  4 13:06:41 1999
@@ -25,6 +25,7 @@
 
 #include <linux/types.h>
 
+#if 0
 /* Mac SCSI Controller 5380 */
 
 #define	MAC_5380_BAS	(0x50F10000) /* This is definitely wrong!! */
@@ -63,65 +64,7 @@
   u_char cha_b_data;
  };
 # define mac_scc ((*(volatile struct SCC*)MAC_SCC_BAS))
-
-/*
-** VIA 6522
-*/
-
-#define VIA1_BAS	(0x50F00000)
-#define VIA2_BAS	(0x50F02000)
-#define VIA2_BAS_IIci	(0x50F26000)
-struct VIA
- {
-  u_char buf_b;
-  u_char dummy1[0x199];
-  u_char buf_a;
-  u_char dummy2[0x199];
-  u_char dir_b;
-  u_char dummy3[0x199];
-  u_char dir_a;
-  u_char dummy4[0x199];
-  u_char timer1_cl;
-  u_char dummy5[0x199];
-  u_char timer1_ch;
-  u_char dummy6[0x199];
-  u_char timer1_ll;
-  u_char dummy7[0x199];
-  u_char timer1_lh;
-  u_char dummy8[0x199];
-  u_char timer2_cl;
-  u_char dummy9[0x199];
-  u_char timer2_ch;
-  u_char dummy10[0x199];
-  u_char sr;
-  u_char dummy11[0x199];
-  u_char acr;
-  u_char dummy12[0x199];
-  u_char pcr;
-  u_char dummy13[0x199];
-  u_char int_fl;
-  u_char dummy14[0x199];
-  u_char int_en;
-  u_char dummy15[0x199];
-  u_char anr;
-  u_char dummy16[0x199];
- };
-
-# define via_1         ((*(volatile struct VIA *)VIA1_BAS))
-# define via_2         ((*(volatile struct VIA *)VIA2_BAS))
-# define via1_regp     ((volatile unsigned char *)VIA1_BAS)
- 
-/*
- * OSS/RBV base address 
- */
-
-#define OSS_BAS		0x50f1a000
-#define PSC_BAS		0x50f31000
-
-/* move to oss.h?? */
-#define nIFR	0x203
-#define oIFR	0x202
-
+#endif
 
 /* hardware stuff */
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/macintosh.h linux/include/asm-m68k/macintosh.h
--- v2.3.16/linux/include/asm-m68k/macintosh.h	Mon Oct  5 13:54:39 1998
+++ linux/include/asm-m68k/macintosh.h	Sat Sep  4 13:06:41 1999
@@ -6,6 +6,7 @@
  */
  
 extern void mac_reset(void);
+extern void mac_poweroff(void);
 extern void mac_init_IRQ(void);
 extern int mac_request_irq (unsigned int, void (*)(int, void *, 
 				struct pt_regs *),
@@ -13,6 +14,7 @@
 extern void mac_free_irq(unsigned int, void *);
 extern void mac_enable_irq(unsigned int);
 extern void mac_disable_irq(unsigned int);
+extern int mac_irq_pending(unsigned int);
 extern int mac_get_irq_list(char *);
 #if 0
 extern void mac_default_handler(int irq);
@@ -21,7 +23,6 @@
 extern void mac_report_hardware(void);
 extern void mac_debugging_penguin(int);
 extern void mac_boom(int);
-extern void mac_video_setup(char *,int *);
 
 /*
  *	Floppy driver magic hook - probably shouldnt be here
@@ -58,6 +59,7 @@
 #define MAC_ADB_CUDA		3
 #define MAC_ADB_PB1		4
 #define MAC_ADB_PB2		5
+#define MAC_ADB_IOP		6
 
 #define MAC_VIA_II		1
 #define MAC_VIA_IIci		2
@@ -131,6 +133,7 @@
 #define MAC_MODEL_P550		80	/* aka: LC550, P560 */
 #define MAC_MODEL_CCLII		83	/* aka: P275 */
 #define MAC_MODEL_PB165		84
+#define MAC_MODEL_PB190		85	/* aka: PB190CS */
 #define MAC_MODEL_TV		88
 #define MAC_MODEL_P475		89	/* aka: LC475, P476 */
 #define MAC_MODEL_P475F		90	/* aka: P475 w/ FPU (no LC040) */
@@ -141,7 +144,6 @@
 #define MAC_MODEL_PB280		102
 #define MAC_MODEL_PB280C	103
 #define MAC_MODEL_PB150		115
-#define MAC_MODEL_PB190		122	/* aka: PB190CS */
 
 extern struct mac_model *macintosh_config;
  
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/macints.h linux/include/asm-m68k/macints.h
--- v2.3.16/linux/include/asm-m68k/macints.h	Sat Jun 13 13:14:33 1998
+++ linux/include/asm-m68k/macints.h	Sat Sep  4 13:06:41 1999
@@ -14,38 +14,49 @@
 
 #include <asm/irq.h>
 
-/*
-** Macintosh Interrupt sources.
-**
-** Note: these are all routed via the generic VIA interrupt routine!
-**
-*/
+/* Setting this prints debugging info for unclaimed interrupts */
+
+#define DEBUG_SPURIOUS
+
+/* Setting this prints debugging info on each autovector interrupt */
+
+/* #define DEBUG_IRQS */
+
+/* Setting this prints debugging info on each Nubus interrupt */
 
-#define SRC_VIA1		0
-#define SRC_VIA2		1
+/* #define DEBUG_NUBUS_INT */
+
+/* Setting this prints debugging info on irqs as they enabled and disabled. */
+
+/* #define DEBUG_IRQUSE */
+
+/*
+ * Base IRQ number for all Mac68K interrupt sources. Each source
+ * has eight indexes (base -> base+7).
+ */
 
 #define VIA1_SOURCE_BASE	8
 #define VIA2_SOURCE_BASE	16
-#define RBV_SOURCE_BASE		24
-#define MAC_SCC_SOURCE_BASE	32
+#define MAC_SCC_SOURCE_BASE	24
+#define PSC3_SOURCE_BASE	24
+#define PSC4_SOURCE_BASE	32
+#define PSC5_SOURCE_BASE	40
+#define PSC6_SOURCE_BASE	48
 #define NUBUS_SOURCE_BASE	56
-#define NUBUS_MAX_SOURCES	8
 
-/* FIXME: sources not contigous ... */
-#define NUM_MAC_SOURCES   (NUBUS_SOURCE_BASE+NUBUS_MAX_SOURCES-VIA1_SOURCE_BASE)
+/*
+ * Maximum IRQ number is NUBUS_SOURCE_BASE + 7,
+ * giving us IRQs up through 63.
+ */
 
-#define IRQ_SRC_MASK (VIA1_SOURCE_BASE|VIA2_SOURCE_BASE|MAC_SCC_SOURCE_BASE)
-#define IRQ_IDX_MASK 7
+#define NUM_MAC_SOURCES		64
 
 /* 
- * quick hack to adapt old MACHSPEC-aware source
+ * clean way to separate IRQ into its source and index
  */
-#define	IRQ_IDX(irq)	(irq)
 
-/* interrupt service types */
-#define IRQ_TYPE_SLOW     0
-#define IRQ_TYPE_FAST     1
-#define IRQ_TYPE_PRIO     2
+#define IRQ_SRC(irq)	(irq >> 3)
+#define	IRQ_IDX(irq)	(irq & 7)
 
 #define	IRQ_SPURIOUS      (0)
 
@@ -59,15 +70,15 @@
 #define IRQ_AUTO_7        (7)
 
 /* VIA1 interrupts */
-#define IRQ_VIA1_0	  (8)	/* one second int. */
-#define IRQ_VIA1_1        (9)	/* VBlank int. */
+#define IRQ_VIA1_0	  (8)		/* one second int. */
+#define IRQ_VIA1_1        (9)		/* VBlank int. */
 #define IRQ_MAC_VBL	  IRQ_VIA1_1
-#define IRQ_VIA1_2 	  (10)	/* ADB SR shifts complete */
+#define IRQ_VIA1_2 	  (10)		/* ADB SR shifts complete */
 #define IRQ_MAC_ADB	  IRQ_VIA1_2
 #define IRQ_MAC_ADB_SR	  IRQ_VIA1_2
-#define IRQ_VIA1_3	  (11)	/* ADB SR CB2 ?? */
+#define IRQ_VIA1_3	  (11)		/* ADB SR CB2 ?? */
 #define IRQ_MAC_ADB_SD	  IRQ_VIA1_3
-#define IRQ_VIA1_4        (12)	/* ADB SR ext. clock pulse */
+#define IRQ_VIA1_4        (12)		/* ADB SR ext. clock pulse */
 #define IRQ_MAC_ADB_CL	  IRQ_VIA1_4
 #define IRQ_VIA1_5	  (13)
 #define IRQ_MAC_TIMER_2	  IRQ_VIA1_5
@@ -75,7 +86,7 @@
 #define IRQ_MAC_TIMER_1	  IRQ_VIA1_6
 #define IRQ_VIA1_7        (15)
 
-/* VIA2 interrupts */
+/* VIA2/RBV interrupts */
 #define IRQ_VIA2_0	  (16)
 #define IRQ_MAC_SCSIDRQ	  IRQ_VIA2_0
 #define IRQ_VIA2_1        (17)
@@ -88,18 +99,6 @@
 #define IRQ_VIA2_6	  (22)
 #define IRQ_VIA2_7        (23)
 
-#if 0
-/* RBV interrupts */
-#define IRQ_RBV_0	  (24)
-#define IRQ_RBV_1	  (25)
-#define IRQ_RBV_2 	  (26)
-#define IRQ_RBV_3	  (27)
-#define IRQ_RBV_4	  (28)
-#define IRQ_RBV_5	  (29)
-#define IRQ_RBV_6	  (30)
-#define IRQ_RBV_7	  (31)
-#endif
-
 /* Level 3 (PSC, AV Macs only) interrupts */
 #define IRQ_PSC3_0	  (24)
 #define IRQ_MAC_MACE	  IRQ_PSC3_0
@@ -109,8 +108,8 @@
 
 /* Level 4 (SCC) interrupts */
 #define IRQ_SCC 	     (32)
-#define IRQ_SCCB	     (33)
-#define IRQ_SCCA	     (34)
+#define IRQ_SCCA	     (33)
+#define IRQ_SCCB	     (34)
 #if 0 /* FIXME: are there multiple interrupt conditions on the SCC ?? */
 /* SCC interrupts */
 #define IRQ_SCCB_TX	     (32)
@@ -143,40 +142,21 @@
 #define IRQ_PSC6_3	  (51)
 
 /* Nubus interrupts (cascaded to VIA2) */
-#define IRQ_NUBUS_1	  (56)
+#define IRQ_NUBUS_9	  (56)
+#define IRQ_NUBUS_A	  (57)
+#define IRQ_NUBUS_B	  (58)
+#define IRQ_NUBUS_C	  (59)
+#define IRQ_NUBUS_D	  (60)
+#define IRQ_NUBUS_E	  (61)
+#define IRQ_NUBUS_F	  (62)
+
+#define SLOT2IRQ(x)	  (x + 47)
+#define IRQ2SLOT(x)	  (x - 47)
 
 #define INT_CLK   24576	    /* CLK while int_clk =2.456MHz and divide = 100 */
 #define INT_TICKS 246	    /* to make sched_time = 99.902... HZ */
 
-
-#define VIA_ENABLE	0
-#define VIA_PENDING	1
-#define VIA_SERVICE	2
-#define VIA_MASK	3
-
-/* 
- * Utility functions for setting/clearing bits in the interrupt registers of
- * the VIA. 
- */
-
-void mac_enable_irq( unsigned irq );
-void mac_disable_irq( unsigned irq );
-void mac_turnon_irq( unsigned irq );
-void mac_turnoff_irq( unsigned irq );
-void mac_clear_pending_irq( unsigned irq );
-int  mac_irq_pending( unsigned irq );
-int  nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct pt_regs *));
-int  nubus_free_irq(int slot);
-
-unsigned long mac_register_nubus_int( void );
-void mac_unregister_nubus_int( unsigned long );
-
-extern void mac_default_handler(int irq, void *dev_id, struct pt_regs *regs);
-extern void via1_irq(int irq, void *dev_id, struct pt_regs *regs);
-extern void via2_irq(int irq, void *dev_id, struct pt_regs *regs);
-extern void  rbv_irq(int irq, void *dev_id, struct pt_regs *regs);
-extern void mac_bang(int irq, void *dev_id, struct pt_regs *regs);
-		
-extern void mac_SCC_handler(int irq, void *dev_id, struct pt_regs *regs);
+extern irq_node_t *mac_irq_list[NUM_MAC_SOURCES];
+extern void mac_do_irq_list(int irq, struct pt_regs *);
 
 #endif /* asm/macints.h */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/mmu_context.h linux/include/asm-m68k/mmu_context.h
--- v2.3.16/linux/include/asm-m68k/mmu_context.h	Mon Aug  9 12:27:31 1999
+++ linux/include/asm-m68k/mmu_context.h	Sat Sep  4 13:06:41 1999
@@ -1,6 +1,8 @@
 #ifndef __M68K_MMU_CONTEXT_H
 #define __M68K_MMU_CONTEXT_H
 
+#ifndef CONFIG_SUN3
+
 #include <asm/setup.h>
 #include <asm/page.h>
 
@@ -90,4 +92,68 @@
 		switch_mm_0460(next_mm);
 }
 
+#else  /* CONFIG_SUN3 */
+#include <asm/sun3mmu.h>
+#include <linux/sched.h>
+
+extern unsigned long get_free_context(struct mm_struct *mm);
+extern void clear_context(unsigned long context);
+extern unsigned char ctx_next_to_die;
+extern unsigned char ctx_live[SUN3_CONTEXTS_NUM];
+
+/* set the context for a new task to unmapped */
+static inline void init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+	mm->context = SUN3_INVALID_CONTEXT;
+}
+
+/* find the context given to this process, and if it hasn't already
+   got one, go get one for it. */
+static inline void get_mmu_context(struct mm_struct *mm)
+{
+	if(mm->context == SUN3_INVALID_CONTEXT)
+		mm->context = get_free_context(mm);
+}
+
+#if 0
+/* we used to clear the context after the process exited.  we still
+   should, things are faster that way...  but very unstable.  so just
+   clear out a context next time we need a new one..  consider this a
+   FIXME. */
+
+/* flush context if allocated... */	
+static inline void destroy_context(struct mm_struct *mm)
+{
+	if(mm->context != SUN3_INVALID_CONTEXT)
+		clear_context(mm->context);
+}
+#else
+/* mark this context as dropped and set it for next death */
+static inline void destroy_context(struct mm_struct *mm) 
+{
+	if(mm->context != SUN3_INVALID_CONTEXT) {
+		ctx_next_to_die = mm->context;
+		ctx_live[mm->context] = 0;
+	}
+}
+#endif
+
+static inline void activate_context(struct mm_struct *mm)
+{
+	get_mmu_context(mm);
+	sun3_put_context(mm->context);
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
+{
+	activate_context(tsk->mm);
+}
+
+extern inline void activate_mm(struct mm_struct *prev_mm,
+			       struct mm_struct *next_mm)
+{
+	activate_context(next_mm);
+}
+
+#endif 
 #endif
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/movs.h linux/include/asm-m68k/movs.h
--- v2.3.16/linux/include/asm-m68k/movs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/movs.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,55 @@
+#ifndef  __MOVS_H__
+#define __MOVS_H__
+
+/*
+** movs.h
+**
+** Inline assembly macros to generate movs & related instructions
+*/
+
+/* Set DFC register value */
+
+#define SET_DFC(x) \
+        __asm__ __volatile__ (" movec %0,%/dfc" : : "d" (x));
+
+/* Get DFC register value */
+
+#define GET_DFC(x) \
+        __asm__ __volatile__ (" movec %/dfc, %0" : "=d" (x) : );
+
+/* Set SFC register value */
+
+#define SET_SFC(x) \
+        __asm__ __volatile__ (" movec %0,%/sfc" : : "d" (x));
+
+/* Get SFC register value */
+
+#define GET_SFC(x) \
+        __asm__ __volatile__ (" movec %/sfc, %0" : "=d" (x) : );
+
+#define SET_VBR(x) \
+        __asm__ __volatile__ (" movec %0,%/vbr" : : "r" (x));
+
+#define GET_VBR(x) \
+        __asm__ __volatile__ (" movec %/vbr, %0" : "=g" (x) : );
+
+/* Set a byte using the "movs" instruction */
+
+#define SET_CONTROL_BYTE(addr,value) \
+        __asm__ __volatile__ (" movsb %0, %1@" : : "d" (value), "a" (addr));
+
+/* Get a byte using the "movs" instruction */
+
+#define GET_CONTROL_BYTE(addr,value) \
+        __asm__ __volatile__ (" movsb %1@, %0" : "=d" (value) : "a" (addr));
+
+/* Set a (long)word using the "movs" instruction */
+
+#define SET_CONTROL_WORD(addr,value) \
+        __asm__ __volatile__ (" movsl %0, %1@" : : "d" (value), "a" (addr));
+
+/* Get a (long)word using the "movs" instruction */
+
+#define GET_CONTROL_WORD(addr,value) \
+        __asm__ __volatile__ (" movsl %1@, %0" : "=d" (value) : "a" (addr));
+#endif
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/openprom.h linux/include/asm-m68k/openprom.h
--- v2.3.16/linux/include/asm-m68k/openprom.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/openprom.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,309 @@
+/* $Id: openprom.h,v 1.19 1996/09/25 03:51:08 davem Exp $ */
+#ifndef __SPARC_OPENPROM_H
+#define __SPARC_OPENPROM_H
+
+/* openprom.h:  Prom structures and defines for access to the OPENBOOT
+ *              prom routines and data areas.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* Empirical constants... */
+#ifdef CONFIG_SUN3
+#define KADB_DEBUGGER_BEGVM     0x0fee0000    /* There is no kadb yet but...*/
+#define LINUX_OPPROM_BEGVM      0x0fef0000
+#define LINUX_OPPROM_ENDVM      0x0ff10000    /* I think this is right - tm */
+#else
+#define KADB_DEBUGGER_BEGVM     0xffc00000    /* Where kern debugger is in virt-mem */
+#define	LINUX_OPPROM_BEGVM	0xffd00000
+#define	LINUX_OPPROM_ENDVM	0xfff00000
+#define	LINUX_OPPROM_MAGIC      0x10010407
+#endif
+
+#ifndef __ASSEMBLY__
+/* V0 prom device operations. */
+struct linux_dev_v0_funcs {
+	int (*v0_devopen)(char *device_str);
+	int (*v0_devclose)(int dev_desc);
+	int (*v0_rdblkdev)(int dev_desc, int num_blks, int blk_st, char *buf);
+	int (*v0_wrblkdev)(int dev_desc, int num_blks, int blk_st, char *buf);
+	int (*v0_wrnetdev)(int dev_desc, int num_bytes, char *buf);
+	int (*v0_rdnetdev)(int dev_desc, int num_bytes, char *buf);
+	int (*v0_rdchardev)(int dev_desc, int num_bytes, int dummy, char *buf);
+	int (*v0_wrchardev)(int dev_desc, int num_bytes, int dummy, char *buf);
+	int (*v0_seekdev)(int dev_desc, long logical_offst, int from);
+};
+
+/* V2 and later prom device operations. */
+struct linux_dev_v2_funcs {
+	int (*v2_inst2pkg)(int d);	/* Convert ihandle to phandle */
+	char * (*v2_dumb_mem_alloc)(char *va, unsigned sz);
+	void (*v2_dumb_mem_free)(char *va, unsigned sz);
+
+	/* To map devices into virtual I/O space. */
+	char * (*v2_dumb_mmap)(char *virta, int which_io, unsigned paddr, unsigned sz);
+	void (*v2_dumb_munmap)(char *virta, unsigned size);
+
+	int (*v2_dev_open)(char *devpath);
+	void (*v2_dev_close)(int d);
+	int (*v2_dev_read)(int d, char *buf, int nbytes);
+	int (*v2_dev_write)(int d, char *buf, int nbytes);
+	int (*v2_dev_seek)(int d, int hi, int lo);
+
+	/* Never issued (multistage load support) */
+	void (*v2_wheee2)(void);
+	void (*v2_wheee3)(void);
+};
+
+struct linux_mlist_v0 {
+	struct linux_mlist_v0 *theres_more;
+	char *start_adr;
+	unsigned num_bytes;
+};
+
+struct linux_mem_v0 {
+	struct linux_mlist_v0 **v0_totphys;
+	struct linux_mlist_v0 **v0_prommap;
+	struct linux_mlist_v0 **v0_available; /* What we can use */
+};
+
+/* Arguments sent to the kernel from the boot prompt. */
+struct linux_arguments_v0 {
+	char *argv[8];
+	char args[100];
+	char boot_dev[2];
+	int boot_dev_ctrl;
+	int boot_dev_unit;
+	int dev_partition;
+	char *kernel_file_name;
+	void *aieee1;           /* XXX */
+};
+
+/* V2 and up boot things. */
+struct linux_bootargs_v2 {
+	char **bootpath;
+	char **bootargs;
+	int *fd_stdin;
+	int *fd_stdout;
+};
+
+#ifdef CONFIG_SUN3
+struct linux_romvec {
+	char		*pv_initsp;		
+	int		(*pv_startmon)(void);
+
+	int		*diagberr;		
+
+	struct linux_arguments_v0 **pv_v0bootargs;
+ 	unsigned	*pv_sun3mem;		
+
+	unsigned char	(*pv_getchar)(void);
+	int		(*pv_putchar)(int ch);
+	int		(*pv_nbgetchar)(void);	
+	int		(*pv_nbputchar)(int ch);
+	unsigned char	*pv_echo;	
+	unsigned char	*pv_insource;
+	unsigned char	*pv_outsink;
+
+	int		(*pv_getkey)(void);		
+	int		(*pv_initgetkey)(void);
+	unsigned int	*pv_translation;
+	unsigned char	*pv_keybid;		
+	int		*pv_screen_x;		
+	int		*pv_screen_y;		
+	struct keybuf	*pv_keybuf;		
+
+	char		*pv_monid;
+
+	/* 
+	 * Frame buffer output and terminal emulation 
+	 */
+
+	int		(*pv_fbwritechar)(char);	
+	int		*pv_fbaddr;		
+	char		**pv_font;		
+	int		(*pv_fbwritestr)(char);	
+
+	void		(*pv_reboot)(char *bootstr);
+
+	/* 
+	 * Line input and parsing 
+	 */
+
+	unsigned char	*pv_linebuf;		
+	unsigned char	**pv_lineptr;		
+	int		*pv_linesize;		
+	int		(*pv_getline)(void);	
+	unsigned char	(*pv_getnextchar)(void);	
+	unsigned char	(*pv_peeknextchar)(void);	
+	int		*pv_fbthere;		
+	int		(*pv_getnum)(void);		
+
+	void		(*pv_printf)(const char *fmt, ...);
+	int		(*pv_printhex)(void);
+
+	unsigned char	*pv_leds;		
+	int		(*pv_setleds)(void);	
+
+	/* 
+	 * Non-maskable interrupt  (nmi) information
+	 */ 
+
+	int		(*pv_nmiaddr)(void);
+	int		(*pv_abortentry)(void);
+	int		*pv_nmiclock;		
+
+	int		*pv_fbtype;
+
+	/* 
+	 * Assorted other things 
+	 */
+
+	unsigned	pv_romvers;
+	struct globram  *pv_globram;		
+	char		*pv_kbdzscc;		
+
+	int		*pv_keyrinit;		
+	unsigned char	*pv_keyrtick; 		
+	unsigned	*pv_memoryavail;	
+	long		*pv_resetaddr;		
+	long		*pv_resetmap;		
+						
+	void		(*pv_halt)(void);	
+	unsigned char	*pv_memorybitmap;	
+	void		(*pv_setctxt)(int ctxt, char *va, int pmeg);
+	void		(*pv_vector_cmd)(void);	
+	int		dummy1z;
+	int		dummy2z;
+	int		dummy3z;
+	int		dummy4z;
+};
+#else
+/* The top level PROM vector. */
+struct linux_romvec {
+	/* Version numbers. */
+	unsigned int pv_magic_cookie;
+	unsigned int pv_romvers;
+	unsigned int pv_plugin_revision;
+	unsigned int pv_printrev;
+
+	/* Version 0 memory descriptors. */
+	struct linux_mem_v0 pv_v0mem;
+
+	/* Node operations. */
+	struct linux_nodeops *pv_nodeops;
+
+	char **pv_bootstr;
+	struct linux_dev_v0_funcs pv_v0devops;
+
+	char *pv_stdin;
+	char *pv_stdout;
+#define	PROMDEV_KBD	0		/* input from keyboard */
+#define	PROMDEV_SCREEN	0		/* output to screen */
+#define	PROMDEV_TTYA	1		/* in/out to ttya */
+#define	PROMDEV_TTYB	2		/* in/out to ttyb */
+
+	/* Blocking getchar/putchar.  NOT REENTRANT! (grr) */
+	int (*pv_getchar)(void);
+	void (*pv_putchar)(int ch);
+
+	/* Non-blocking variants. */
+	int (*pv_nbgetchar)(void);
+	int (*pv_nbputchar)(int ch);
+
+	void (*pv_putstr)(char *str, int len);
+
+	/* Miscellany. */
+	void (*pv_reboot)(char *bootstr);
+	void (*pv_printf)(__const__ char *fmt, ...);
+	void (*pv_abort)(void);
+	__volatile__ int *pv_ticks;
+	void (*pv_halt)(void);
+	void (**pv_synchook)(void);
+
+	/* Evaluate a forth string, not different proto for V0 and V2->up. */
+	union {
+		void (*v0_eval)(int len, char *str);
+		void (*v2_eval)(char *str);
+	} pv_fortheval;
+
+	struct linux_arguments_v0 **pv_v0bootargs;
+
+	/* Get ether address. */
+	unsigned int (*pv_enaddr)(int d, char *enaddr);
+
+	struct linux_bootargs_v2 pv_v2bootargs;
+	struct linux_dev_v2_funcs pv_v2devops;
+
+	int filler[15];
+
+	/* This one is sun4c/sun4 only. */
+	void (*pv_setctxt)(int ctxt, char *va, int pmeg);
+
+	/* Prom version 3 Multiprocessor routines. This stuff is crazy.
+	 * No joke. Calling these when there is only one cpu probably
+	 * crashes the machine, have to test this. :-)
+	 */
+
+	/* v3_cpustart() will start the cpu 'whichcpu' in mmu-context
+	 * 'thiscontext' executing at address 'prog_counter'
+	 */
+	int (*v3_cpustart)(unsigned int whichcpu, int ctxtbl_ptr,
+			   int thiscontext, char *prog_counter);
+
+	/* v3_cpustop() will cause cpu 'whichcpu' to stop executing
+	 * until a resume cpu call is made.
+	 */
+	int (*v3_cpustop)(unsigned int whichcpu);
+
+	/* v3_cpuidle() will idle cpu 'whichcpu' until a stop or
+	 * resume cpu call is made.
+	 */
+	int (*v3_cpuidle)(unsigned int whichcpu);
+
+	/* v3_cpuresume() will resume processor 'whichcpu' executing
+	 * starting with whatever 'pc' and 'npc' were left at the
+	 * last 'idle' or 'stop' call.
+	 */
+	int (*v3_cpuresume)(unsigned int whichcpu);
+};
+#endif
+
+/* Routines for traversing the prom device tree. */
+struct linux_nodeops {
+	int (*no_nextnode)(int node);
+	int (*no_child)(int node);
+	int (*no_proplen)(int node, char *name);
+	int (*no_getprop)(int node, char *name, char *val);
+	int (*no_setprop)(int node, char *name, char *val, int len);
+	char * (*no_nextprop)(int node, char *name);
+};
+
+/* More fun PROM structures for device probing. */
+#define PROMREG_MAX     16
+#define PROMVADDR_MAX   16
+#define PROMINTR_MAX    15
+
+struct linux_prom_registers {
+	int which_io;         /* is this in OBIO space? */
+	char *phys_addr;      /* The physical address of this register */
+	int reg_size;         /* How many bytes does this register take up? */
+};
+
+struct linux_prom_irqs {
+	int pri;    /* IRQ priority */
+	int vector; /* This is foobar, what does it do? */
+};
+
+/* Element of the "ranges" vector */
+struct linux_prom_ranges {
+	unsigned int ot_child_space;
+	unsigned int ot_child_base;		/* Bus feels this */
+	unsigned int ot_parent_space;
+	unsigned int ot_parent_base;		/* CPU looks from here */
+	unsigned int or_size;
+};
+
+#endif /* !(__ASSEMBLY__) */
+
+#endif /* !(__SPARC_OPENPROM_H) */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/oplib.h linux/include/asm-m68k/oplib.h
--- v2.3.16/linux/include/asm-m68k/oplib.h	Tue May 11 09:57:14 1999
+++ linux/include/asm-m68k/oplib.h	Sat Sep  4 13:06:41 1999
@@ -1,8 +1,297 @@
-/*
- * prototypes for dummy prom_* routines
+/* $Id: oplib.h,v 1.12 1996/10/31 06:29:13 davem Exp $
+ * oplib.h:  Describes the interface and available routines in the
+ *           Linux Prom library.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#ifndef __SPARC_OPLIB_H
+#define __SPARC_OPLIB_H
+
+#include <asm/openprom.h>
+
+/* The master romvec pointer... */
+extern struct linux_romvec *romvec;
+
+/* Enumeration to describe the prom major version we have detected. */
+enum prom_major_version {
+	PROM_V0,      /* Original sun4c V0 prom */
+	PROM_V2,      /* sun4c and early sun4m V2 prom */
+	PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
+	PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
+        PROM_AP1000,  /* actually no prom at all */
+};
+
+extern enum prom_major_version prom_vers;
+/* Revision, and firmware revision. */
+extern unsigned int prom_rev, prom_prev;
+
+/* Root node of the prom device tree, this stays constant after
+ * initialization is complete.
+ */
+extern int prom_root_node;
+
+/* Pointer to prom structure containing the device tree traversal
+ * and usage utility functions.  Only prom-lib should use these,
+ * users use the interface defined by the library only!
+ */
+extern struct linux_nodeops *prom_nodeops;
+
+/* The functions... */
+
+/* You must call prom_init() before using any of the library services,
+ * preferably as early as possible.  Pass it the romvec pointer.
+ */
+extern void prom_init(struct linux_romvec *rom_ptr);
+
+/* Boot argument acquisition, returns the boot command line string. */
+extern char *prom_getbootargs(void);
+
+/* Device utilities. */
+
+/* Map and unmap devices in IO space at virtual addresses. Note that the
+ * virtual address you pass is a request and the prom may put your mappings
+ * somewhere else, so check your return value as that is where your new
+ * mappings really are!
+ *
+ * Another note, these are only available on V2 or higher proms!
+ */
+extern char *prom_mapio(char *virt_hint, int io_space, unsigned int phys_addr, unsigned int num_bytes);
+extern void prom_unmapio(char *virt_addr, unsigned int num_bytes);
+
+/* Device operations. */
+
+/* Open the device described by the passed string.  Note, that the format
+ * of the string is different on V0 vs. V2->higher proms.  The caller must
+ * know what he/she is doing!  Returns the device descriptor, an int.
+ */
+extern int prom_devopen(char *device_string);
+
+/* Close a previously opened device described by the passed integer
+ * descriptor.
+ */
+extern int prom_devclose(int device_handle);
+
+/* Do a seek operation on the device described by the passed integer
+ * descriptor.
+ */
+extern void prom_seek(int device_handle, unsigned int seek_hival,
+		      unsigned int seek_lowval);
+
+/* Machine memory configuration routine. */
+
+/* This function returns a V0 format memory descriptor table, it has three
+ * entries.  One for the total amount of physical ram on the machine, one
+ * for the amount of physical ram available, and one describing the virtual
+ * areas which are allocated by the prom.  So, in a sense the physical
+ * available is a calculation of the total physical minus the physical mapped
+ * by the prom with virtual mappings.
+ *
+ * These lists are returned pre-sorted, this should make your life easier
+ * since the prom itself is way too lazy to do such nice things.
+ */
+extern struct linux_mem_v0 *prom_meminfo(void);
+
+/* Miscellaneous routines, don't really fit in any category per se. */
+
+/* Reboot the machine with the command line passed. */
+extern void prom_reboot(char *boot_command);
+
+/* Evaluate the forth string passed. */
+extern void prom_feval(char *forth_string);
+
+/* Enter the prom, with possibility of continuation with the 'go'
+ * command in newer proms.
+ */
+extern void prom_cmdline(void);
+
+/* Enter the prom, with no chance of continuation for the stand-alone
+ * which calls this.
+ */
+extern void prom_halt(void);
+
+/* Set the PROM 'sync' callback function to the passed function pointer.
+ * When the user gives the 'sync' command at the prom prompt while the
+ * kernel is still active, the prom will call this routine.
+ *
+ * XXX The arguments are different on V0 vs. V2->higher proms, grrr! XXX
+ */
+typedef void (*sync_func_t)(void);
+extern void prom_setsync(sync_func_t func_ptr);
+
+/* Acquire the IDPROM of the root node in the prom device tree.  This
+ * gets passed a buffer where you would like it stuffed.  The return value
+ * is the format type of this idprom or 0xff on error.
+ */
+extern unsigned char prom_get_idprom(char *idp_buffer, int idpbuf_size);
+
+/* Get the prom major version. */
+extern int prom_version(void);
+
+/* Get the prom plugin revision. */
+extern int prom_getrev(void);
+
+/* Get the prom firmware revision. */
+extern int prom_getprev(void);
+
+/* Character operations to/from the console.... */
+
+/* Non-blocking get character from console. */
+extern int prom_nbgetchar(void);
+
+/* Non-blocking put character to console. */
+extern int prom_nbputchar(char character);
+
+/* Blocking get character from console. */
+extern char prom_getchar(void);
+
+/* Blocking put character to console. */
+extern void prom_putchar(char character);
+
+/* Prom's internal printf routine, don't use in kernel/boot code. */
+void prom_printf(char *fmt, ...);
+
+/* Query for input device type */
+
+enum prom_input_device {
+	PROMDEV_IKBD,			/* input from keyboard */
+	PROMDEV_ITTYA,			/* input from ttya */
+	PROMDEV_ITTYB,			/* input from ttyb */
+	PROMDEV_I_UNK,
+};
+
+extern enum prom_input_device prom_query_input_device(void);
+
+/* Query for output device type */
+
+enum prom_output_device {
+	PROMDEV_OSCREEN,		/* to screen */
+	PROMDEV_OTTYA,			/* to ttya */
+	PROMDEV_OTTYB,			/* to ttyb */
+	PROMDEV_O_UNK,
+};
+
+extern enum prom_output_device prom_query_output_device(void);
+
+/* Multiprocessor operations... */
+
+/* Start the CPU with the given device tree node, context table, and context
+ * at the passed program counter.
+ */
+extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table,
+			 int context, char *program_counter);
+
+/* Stop the CPU with the passed device tree node. */
+extern int prom_stopcpu(int cpunode);
+
+/* Idle the CPU with the passed device tree node. */
+extern int prom_idlecpu(int cpunode);
+
+/* Re-Start the CPU with the passed device tree node. */
+extern int prom_restartcpu(int cpunode);
+
+/* PROM memory allocation facilities... */
+
+/* Allocated at possibly the given virtual address a chunk of the
+ * indicated size.
+ */
+extern char *prom_alloc(char *virt_hint, unsigned int size);
+
+/* Free a previously allocated chunk. */
+extern void prom_free(char *virt_addr, unsigned int size);
+
+/* Sun4/sun4c specific memory-management startup hook. */
+
+/* Map the passed segment in the given context at the passed
+ * virtual address.
+ */
+extern void prom_putsegment(int context, unsigned long virt_addr,
+			    int physical_segment);
+
+/* PROM device tree traversal functions... */
+
+/* Get the child node of the given node, or zero if no child exists. */
+extern int prom_getchild(int parent_node);
+
+/* Get the next sibling node of the given node, or zero if no further
+ * siblings exist.
+ */
+extern int prom_getsibling(int node);
+
+/* Get the length, at the passed node, of the given property type.
+ * Returns -1 on error (ie. no such property at this node).
+ */
+extern int prom_getproplen(int thisnode, char *property);
+
+/* Fetch the requested property using the given buffer.  Returns
+ * the number of bytes the prom put into your buffer or -1 on error.
+ */
+extern int prom_getproperty(int thisnode, char *property,
+			    char *prop_buffer, int propbuf_size);
+
+/* Acquire an integer property. */
+extern int prom_getint(int node, char *property);
+
+/* Acquire an integer property, with a default value. */
 extern int prom_getintdefault(int node, char *property, int defval);
+
+/* Acquire a boolean property, 0=FALSE 1=TRUE. */
 extern int prom_getbool(int node, char *prop);
-extern void prom_printf(char *fmt, ...);
-extern void prom_halt(void) __attribute__ ((noreturn));
+
+/* Acquire a string property, null string on error. */
+extern void prom_getstring(int node, char *prop, char *buf, int bufsize);
+
+/* Does the passed node have the given "name"? YES=1 NO=0 */
+extern int prom_nodematch(int thisnode, char *name);
+
+/* Puts in buffer a prom name in the form name@x,y or name (x for which_io 
+ * and y for first regs phys address
+ */
+extern int prom_getname(int node, char *buf, int buflen);
+
+/* Search all siblings starting at the passed node for "name" matching
+ * the given string.  Returns the node on success, zero on failure.
+ */
+extern int prom_searchsiblings(int node_start, char *name);
+
+/* Return the first property type, as a string, for the given node.
+ * Returns a null string on error.
+ */
+extern char *prom_firstprop(int node);
+
+/* Returns the next property after the passed property for the given
+ * node.  Returns null string on failure.
+ */
+extern char *prom_nextprop(int node, char *prev_property);
+
+/* Returns 1 if the specified node has given property. */
+extern int prom_node_has_property(int node, char *property);
+
+/* Set the indicated property at the given node with the passed value.
+ * Returns the number of bytes of your value that the prom took.
+ */
+extern int prom_setprop(int node, char *prop_name, char *prop_value,
+			int value_size);
+			
+extern int prom_pathtoinode(char *path);
+extern int prom_inst2pkg(int);
+
+/* Dorking with Bus ranges... */
+
+/* Adjust reg values with the passed ranges. */
+extern void prom_adjust_regs(struct linux_prom_registers *regp, int nregs,
+			     struct linux_prom_ranges *rangep, int nranges);
+
+/* Adjust child ranges with the passed parent ranges. */
+extern void prom_adjust_ranges(struct linux_prom_ranges *cranges, int ncranges,
+			       struct linux_prom_ranges *pranges, int npranges);
+
+/* Apply promlib probed OBIO ranges to registers. */
+extern void prom_apply_obio_ranges(struct linux_prom_registers *obioregs, int nregs);
+
+/* Apply ranges of any prom node (and optionally parent node as well) to registers. */
+extern void prom_apply_generic_ranges(int node, int parent, 
+				      struct linux_prom_registers *sbusregs, int nregs);
+				   
+
+#endif /* !(__SPARC_OPLIB_H) */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/page.h linux/include/asm-m68k/page.h
--- v2.3.16/linux/include/asm-m68k/page.h	Mon Aug  9 12:27:31 1999
+++ linux/include/asm-m68k/page.h	Sat Sep  4 13:06:41 1999
@@ -4,14 +4,27 @@
 #include <linux/config.h>
 
 /* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT	12
-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#ifndef CONFIG_SUN3
+#define PAGE_SHIFT	(12)
+#define PAGE_SIZE	(4096)
+#else
+#define PAGE_SHIFT	(13)
+#define PAGE_SIZE	(8192)
+#endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
 #ifdef __KERNEL__
 
 #include <asm/setup.h>
 
+#if PAGE_SHIFT < 13
+#define KTHREAD_SIZE (8192)
+#else
+#define KTHREAD_SIZE PAGE_SIZE
+#endif
+ 
+#ifndef __ASSEMBLY__
+ 
 #define STRICT_MM_TYPECHECKS
 
 #define get_user_page(vaddr)	__get_free_page(GFP_KERNEL)
@@ -110,7 +123,13 @@
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 /* This handles the memory map.. */
+#ifndef CONFIG_SUN3
 #define PAGE_OFFSET		0
+#else
+#define PAGE_OFFSET		0x0E000000
+#endif
+
+#ifndef CONFIG_SUN3
 #define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
 /*
  * A hacky workaround for the problems with mmap() of frame buffer
@@ -128,12 +147,46 @@
 #endif
 		return (void *)(physaddr+PAGE_OFFSET);
 }
+#else	/* !CONFIG_SUN3 */
+/* This #define is a horrible hack to suppress lots of warnings. --m */
+#define __pa(x) ___pa((unsigned long)x)
+static inline unsigned long ___pa(unsigned long x)
+{
+     if(x == 0)
+	  return 0;
+     if(x > PAGE_OFFSET)
+        return (x-PAGE_OFFSET);
+     else
+        return (x+0x2000000);
+}
+
+static inline void *__va(unsigned long x)
+{
+     if(x == 0)
+	  return (void *)0;
+
+     if(x < 0x2000000)
+        return (void *)(x+PAGE_OFFSET);
+     else
+        return (void *)(x-0x2000000);
+}
+#endif	/* CONFIG_SUN3 */
+
 #define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 
+#endif /* !__ASSEMBLY__ */
+
+#ifndef CONFIG_SUN3
 #define BUG() do { \
 	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
 	asm volatile("illegal"); \
 } while (0)
+#else
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	panic("BUG!"); \
+} while (0)
+#endif
 
 #define PAGE_BUG(page) do { \
 	BUG(); \
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/param.h linux/include/asm-m68k/param.h
--- v2.3.16/linux/include/asm-m68k/param.h	Wed Dec 27 12:47:20 1995
+++ linux/include/asm-m68k/param.h	Sat Sep  4 13:06:41 1999
@@ -5,7 +5,11 @@
 #define HZ 100
 #endif
 
+#ifndef CONFIG_SUN3
 #define EXEC_PAGESIZE	4096
+#else
+#define EXEC_PAGESIZE	8192
+#endif
 
 #ifndef NGROUPS
 #define NGROUPS		32
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.3.16/linux/include/asm-m68k/pgtable.h	Thu Aug 26 13:05:41 1999
+++ linux/include/asm-m68k/pgtable.h	Sat Sep  4 13:06:41 1999
@@ -300,6 +300,14 @@
 #define _PAGE_CACHE040	0x020	/* 68040 cache mode, cachable, copyback */
 #define _PAGE_CACHE040W	0x000	/* 68040 cache mode, cachable, write-through */
 
+/* Page protection values within PTE. */
+#define SUN3_PAGE_VALID     (0x80000000)
+#define SUN3_PAGE_WRITEABLE (0x40000000)
+#define SUN3_PAGE_SYSTEM    (0x20000000)
+#define SUN3_PAGE_NOCACHE   (0x10000000)
+#define SUN3_PAGE_ACCESSED  (0x02000000)
+#define SUN3_PAGE_MODIFIED  (0x01000000)
+
 #define _DESCTYPE_MASK	0x003
 
 #define _CACHEMASK040	(~0x060)
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/processor.h linux/include/asm-m68k/processor.h
--- v2.3.16/linux/include/asm-m68k/processor.h	Mon Aug  9 12:27:31 1999
+++ linux/include/asm-m68k/processor.h	Sat Sep  4 13:06:41 1999
@@ -32,12 +32,24 @@
  * User space process size: 3.75GB. This is hardcoded into a few places,
  * so don't change it unless you know what you are doing.
  */
+#ifndef CONFIG_SUN3
 #define TASK_SIZE	(0xF0000000UL)
+#else
+#ifdef __ASSEMBLY__
+#define TASK_SIZE	(0x0E000000)
+#else
+#define TASK_SIZE	(0x0E000000UL)
+#endif
+#endif
 
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
+#ifndef CONFIG_SUN3
 #define TASK_UNMAPPED_BASE	0xC0000000UL
+#else
+#define TASK_UNMAPPED_BASE	0x0A000000UL
+#endif
 #define TASK_UNMAPPED_ALIGN(addr, off)	PAGE_ALIGN(addr)
 
 /*
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sbus.h linux/include/asm-m68k/sbus.h
--- v2.3.16/linux/include/asm-m68k/sbus.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sbus.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,20 @@
+/*
+ * some sbus structures and macros to make usage of sbus drivers possible
+ */
+
+#ifndef __M68K_SBUS_H
+#define __M68K_SBUS_H
+
+struct linux_sbus_device {
+	struct {
+		unsigned int which_io;
+		unsigned int phys_addr;
+	} reg_addrs[1];
+};
+
+extern void *sparc_alloc_io (u32, void *, int, char *, u32, int);
+#define sparc_alloc_io(a,b,c,d,e,f)	(a)
+
+#define ARCH_SUN4  0
+
+#endif
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/setup.h linux/include/asm-m68k/setup.h
--- v2.3.16/linux/include/asm-m68k/setup.h	Sun Aug 15 11:47:29 1999
+++ linux/include/asm-m68k/setup.h	Sat Sep  4 13:06:41 1999
@@ -88,7 +88,9 @@
 #endif
 
 #if defined(CONFIG_SUN3)
-#  error Currently no Sun-3 support!
+#define MACH_IS_SUN3 (1)
+#define MACH_SUN3_ONLY (1)
+#define MACH_TYPE (MACH_SUN3)
 #else
 #define MACH_IS_SUN3 (0)
 #endif
@@ -243,7 +245,7 @@
 #ifndef __ASSEMBLY__
 extern unsigned long m68k_cputype;
 extern unsigned long m68k_fputype;
-extern unsigned long m68k_mmutype;			/* Not really used yet */
+extern unsigned long m68k_mmutype;		/* Not really used yet */
 
     /*
      *  m68k_is040or060 is != 0 for a '040 or higher;
@@ -255,38 +257,58 @@
 
 #if !defined(CONFIG_M68020)
 #  define CPU_IS_020 (0)
+#  define MMU_IS_851 (0)
+#  define MMU_IS_SUN3 (0)
 #elif defined(CONFIG_M68030) || defined(CONFIG_M68040) || defined(CONFIG_M68060)
 #  define CPU_IS_020 (m68k_cputype & CPU_68020)
+#  define MMU_IS_851 (m68k_cputype & MMU_68851)
+#  define MMU_IS_SUN3 (0)	/* Sun3 not supported with other CPU enabled */
 #else
 #  define CPU_M68020_ONLY
 #  define CPU_IS_020 (1)
+#ifdef MACH_SUN3_ONLY
+#  define MMU_IS_SUN3 (1)
+#  define MMU_IS_851 (0)
+#else
+#  define MMU_IS_SUN3 (0)
+#  define MMU_IS_851 (1)
+#endif
 #endif
 
 #if !defined(CONFIG_M68030)
 #  define CPU_IS_030 (0)
+#  define MMU_IS_030 (0)
 #elif defined(CONFIG_M68020) || defined(CONFIG_M68040) || defined(CONFIG_M68060)
 #  define CPU_IS_030 (m68k_cputype & CPU_68030)
+#  define MMU_IS_030 (m68k_mmutype & MMU_68030)
 #else
 #  define CPU_M68030_ONLY
 #  define CPU_IS_030 (1)
+#  define MMU_IS_030 (1)
 #endif
 
 #if !defined(CONFIG_M68040)
 #  define CPU_IS_040 (0)
+#  define MMU_IS_040 (0)
 #elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68060)
 #  define CPU_IS_040 (m68k_cputype & CPU_68040)
+#  define MMU_IS_040 (m68k_mmutype & MMU_68040)
 #else
 #  define CPU_M68040_ONLY
 #  define CPU_IS_040 (1)
+#  define MMU_IS_040 (1)
 #endif
 
 #if !defined(CONFIG_M68060)
 #  define CPU_IS_060 (0)
+#  define MMU_IS_060 (0)
 #elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68040)
 #  define CPU_IS_060 (m68k_cputype & CPU_68060)
+#  define MMU_IS_060 (m68k_mmutype & MMU_68060)
 #else
 #  define CPU_M68060_ONLY
 #  define CPU_IS_060 (1)
+#  define MMU_IS_060 (1)
 #endif
 
 #if !defined(CONFIG_M68020) && !defined(CONFIG_M68030)
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/shm.h linux/include/asm-m68k/shm.h
--- v2.3.16/linux/include/asm-m68k/shm.h	Wed Dec 27 12:47:22 1995
+++ linux/include/asm-m68k/shm.h	Sat Sep  4 13:06:41 1999
@@ -12,8 +12,14 @@
    bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
 */
 /* on the m68k both bits 0 and 1 must be zero */
+/* format on the sun3 is similar, but bits 30, 31 are set to zero and all
+   others are reduced by 2. --m */
 
+#ifndef CONFIG_SUN3
 #define SHM_ID_SHIFT	9
+#else
+#define SHM_ID_SHIFT	7
+#endif
 #define _SHM_ID_BITS	7
 #define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/shmparam.h linux/include/asm-m68k/shmparam.h
--- v2.3.16/linux/include/asm-m68k/shmparam.h	Sat Mar 30 04:11:42 1996
+++ linux/include/asm-m68k/shmparam.h	Sat Sep  4 13:06:41 1999
@@ -2,8 +2,13 @@
 #define _M68K_SHMPARAM_H
 
 /* address range for shared memory attaches if no address passed to shmat() */
+#ifndef CONFIG_SUN3
 #define SHM_RANGE_START	0xC0000000
 #define SHM_RANGE_END	0xD0000000
+#else
+#define SHM_RANGE_START	0x0C000000
+#define SHM_RANGE_END	0x0D000000
+#endif
 
 /*
  * Format of a swap-entry for shared memory pages currently out in
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sun3-head.h linux/include/asm-m68k/sun3-head.h
--- v2.3.16/linux/include/asm-m68k/sun3-head.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3-head.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,12 @@
+/* $Id: head.h,v 1.32 1996/12/04 00:12:48 ecd Exp $ */
+#ifndef __SUN3_HEAD_H
+#define __SUN3_HEAD_H
+
+#define KERNBASE        0xE000000  /* First address the kernel will eventually be */
+#define LOAD_ADDR       0x4000      /* prom jumps to us here unless this is elf /boot */
+#define BI_START (KERNBASE + 0x3000) /* beginning of the bootinfo records */
+#define FC_CONTROL  3
+#define FC_SUPERD    5
+#define FC_CPU      7
+
+#endif __SUN3_HEAD_H
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sun3ints.h linux/include/asm-m68k/sun3ints.h
--- v2.3.16/linux/include/asm-m68k/sun3ints.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3ints.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,31 @@
+/*
+ * sun3ints.h -- Linux/Sun3 interrupt handling code definitions
+ *
+ * Erik Verbruggen (erik@bigmama.xtdnet.nl)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#ifndef SUN3INTS_H
+#define SUN3INTS_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <asm/segment.h>
+#include <asm/intersil.h>
+#include <asm/oplib.h>
+
+void sun3_enable_irq(unsigned int irq);
+void sun3_disable_irq(unsigned int irq);
+int sun3_request_irq(unsigned int irq,
+                     void (*handler)(int, void *, struct pt_regs *),
+                     unsigned long flags, const char *devname, void *dev_id
+		    );
+
+#endif /* SUN3INTS_H */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/sun3mmu.h linux/include/asm-m68k/sun3mmu.h
--- v2.3.16/linux/include/asm-m68k/sun3mmu.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/sun3mmu.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,167 @@
+/*
+ * Definitions for Sun3 custom MMU.
+ */
+#include <asm/movs.h>
+
+#ifndef __SUN3_MMU_H__
+#define __SUN3_MMU_H__
+
+#define FC_CONTROL 3
+
+/* MMU characteristics. */
+#define SUN3_SEGMAPS_PER_CONTEXT	2048
+#define SUN3_PMEGS_NUM			256
+#define SUN3_CONTEXTS_NUM               8
+
+#define SUN3_PMEG_SIZE_BITS	 17
+#define SUN3_PMEG_SIZE		 (1 << SUN3_PMEG_SIZE_BITS)
+#define SUN3_PMEG_MASK		 (SUN3_PMEG_SIZE - 1)
+
+#define SUN3_PTE_SIZE_BITS       13
+#define SUN3_PTE_SIZE		 (1 << SUN3_PTE_SIZE_BITS)
+#define SUN3_PTE_MASK		 (SUN3_PTE_SIZE - 1)
+
+#define SUN3_CONTROL_MASK       (0x0FFFFFFC)
+#define SUN3_INVALID_PMEG	255
+#define SUN3_INVALID_CONTEXT 255
+
+#define AC_IDPROM     0x00000000    /* 34  ID PROM, R/O, byte, 32 bytes      */
+#define AC_PAGEMAP    0x10000000    /* 3   Pagemap R/W, long                 */
+#define AC_SEGMAP     0x20000000    /* 3   Segment map, byte                 */
+#define AC_CONTEXT    0x30000000    /* 34c current mmu-context               */
+#define AC_SENABLE    0x40000000    /* 34c system dvma/cache/reset enable reg*/
+#define AC_UDVMA_ENB  0x50000000    /* 34  Not used on Sun boards, byte      */
+#define AC_BUS_ERROR  0x60000000    /* 34  Cleared on read, byte.            */
+#define AC_SYNC_ERR   0x60000000    /*   c fault type                        */
+#define AC_SYNC_VA    0x60000004    /*   c fault virtual address             */
+#define AC_ASYNC_ERR  0x60000008    /*   c asynchronous fault type           */
+#define AC_ASYNC_VA   0x6000000c    /*   c async fault virtual address       */
+#define AC_LEDS       0x70000000    /* 34  Zero turns on LEDs, byte          */
+#define AC_CACHETAGS  0x80000000    /* 34c direct access to the VAC tags     */
+#define AC_CACHEDDATA 0x90000000    /* 3 c direct access to the VAC data     */
+#define AC_UDVMA_MAP  0xD0000000    /* 4   Not used on Sun boards, byte      */
+#define AC_VME_VECTOR 0xE0000000    /* 4   For non-Autovector VME, byte      */
+#define AC_BOOT_SCC   0xF0000000    /* 34  bypass to access Zilog 8530. byte.*/
+
+#define SUN3_PAGE_CHG_MASK (SUN3_PAGE_PGNUM_MASK \
+			    | SUN3_PAGE_ACCESSED | SUN3_PAGE_MODIFIED)
+
+/* Bus access type within PTE. */
+#define SUN3_PAGE_TYPE_MASK   (0x0c000000)
+#define SUN3_PAGE_TYPE_MEMORY (0x00000000)
+#define SUN3_PAGE_TYPE_IO     (0x04000000)
+#define SUN3_PAGE_TYPE_VME16  (0x08000000)
+#define SUN3_PAGE_TYPE_VME32  (0x0c000000)
+
+/* Mask for page number within PTE. */
+#define SUN3_PAGE_PGNUM_MASK (0x0007FFFF)
+
+/* Bits within bus-error register. */
+#define SUN3_BUSERR_WATCHDOG	(0x01)
+#define SUN3_BUSERR_unused	(0x02)
+#define SUN3_BUSERR_FPAENERR	(0x04)
+#define SUN3_BUSERR_FPABERR	(0x08)
+#define SUN3_BUSERR_VMEBERR	(0x10)
+#define SUN3_BUSERR_TIMEOUT	(0x20)
+#define SUN3_BUSERR_PROTERR	(0x40)
+#define SUN3_BUSERR_INVALID	(0x80)
+
+#ifndef __ASSEMBLY__
+
+/* Read bus error status register (implicitly clearing it). */
+extern __inline__ unsigned char sun3_get_buserr (void)
+{
+	unsigned char sfc, c;
+
+	GET_SFC (sfc);
+	SET_SFC (FC_CONTROL);
+	GET_CONTROL_BYTE (AC_BUS_ERROR, c);
+	SET_SFC (sfc);
+
+	return c;
+}
+
+/* Read segmap from hardware MMU. */
+extern __inline__ unsigned long sun3_get_segmap (unsigned long addr)
+{
+        register unsigned long entry;
+        unsigned char c, sfc;
+
+        GET_SFC (sfc);
+        SET_SFC (FC_CONTROL);
+        GET_CONTROL_BYTE (AC_SEGMAP | (addr & SUN3_CONTROL_MASK), c);
+        SET_SFC (sfc);
+        entry = c;
+
+        return entry;
+}
+
+/* Write segmap to hardware MMU. */
+extern __inline__ void sun3_put_segmap (unsigned long addr, unsigned long entry)
+{
+        unsigned char sfc;
+
+        GET_DFC (sfc);
+        SET_DFC (FC_CONTROL);
+        SET_CONTROL_BYTE (AC_SEGMAP | (addr & SUN3_CONTROL_MASK), entry);
+	SET_DFC (sfc);
+
+        return;
+}
+
+/* Read PTE from hardware MMU. */
+extern __inline__ unsigned long sun3_get_pte (unsigned long addr)
+{
+        register unsigned long entry;
+        unsigned char sfc;
+
+        GET_SFC (sfc);
+        SET_SFC (FC_CONTROL);
+        GET_CONTROL_WORD (AC_PAGEMAP | (addr & SUN3_CONTROL_MASK), entry);
+        SET_SFC (sfc);
+
+        return entry;
+}
+
+/* Write PTE to hardware MMU. */
+extern __inline__ void sun3_put_pte (unsigned long addr, unsigned long entry)
+{
+        unsigned char sfc;
+
+        GET_DFC (sfc);
+        SET_DFC (FC_CONTROL);
+        SET_CONTROL_WORD (AC_PAGEMAP | (addr & SUN3_CONTROL_MASK), entry);
+	SET_DFC (sfc);
+
+        return;
+}
+
+/* get current context */
+extern __inline__ unsigned char sun3_get_context(void)
+{
+	unsigned char sfc, c;
+
+	GET_SFC(sfc);
+	SET_SFC(FC_CONTROL);
+	GET_CONTROL_BYTE(AC_CONTEXT, c);
+	SET_SFC(sfc);
+	
+	return c;
+}
+
+/* set alternate context */
+extern __inline__ void sun3_put_context(unsigned char c)
+{
+	unsigned char dfc;
+	GET_DFC(dfc);
+	SET_DFC(FC_CONTROL);
+	SET_CONTROL_BYTE(AC_CONTEXT, c);
+	SET_DFC(dfc);
+	
+	return;
+}
+
+
+#endif	/* !__ASSEMBLY__ */
+
+#endif	/* !__SUN3_MMU_H__ */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/swim_iop.h linux/include/asm-m68k/swim_iop.h
--- v2.3.16/linux/include/asm-m68k/swim_iop.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/swim_iop.h	Sat Sep  4 13:06:41 1999
@@ -0,0 +1,221 @@
+/*
+ * SWIM access through the IOP
+ * Written by Joshua M. Thompson
+ */
+
+/* IOP number and channel number for the SWIM */
+
+#define SWIM_IOP	IOP_NUM_ISM
+#define SWIM_CHAN	1
+
+/* Command code: */
+
+#define CMD_INIT		0x01	/* Initialize                  */
+#define CMD_SHUTDOWN		0x02	/* Shutdown                    */
+#define CMD_START_POLL		0x03	/* Start insert/eject polling  */
+#define CMD_STOP_POLL		0x04	/* Stop insert/eject polling   */
+#define CMD_SETHFSTAG		0x05	/* Set HFS tag buffer address  */
+#define CMD_STATUS		0x06	/* Status                      */
+#define CMD_EJECT		0x07	/* Eject                       */
+#define CMD_FORMAT		0x08	/* Format                      */
+#define CMD_FORMAT_VERIFY	0x09	/* Format and Verify           */
+#define CMD_WRITE		0x0A	/* Write                       */
+#define CMD_READ		0x0B	/* Read                        */
+#define CMD_READ_VERIFY		0x0C	/* Read and Verify             */
+#define CMD_CACHE_CTRL		0x0D	/* Cache control               */
+#define CMD_TAGBUFF_CTRL	0x0E	/* Tag buffer control          */
+#define CMD_GET_ICON		0x0F	/* Get Icon                    */
+
+/* Drive types: */
+
+/* note: apple sez DRV_FDHD is 4, but I get back a type */
+/*       of 5 when I do a drive status check on my FDHD */
+
+#define	DRV_NONE	0	/* No drive             */
+#define	DRV_UNKNOWN	1	/* Unspecified drive    */
+#define	DRV_400K	2	/* 400K                 */
+#define	DRV_800K	3	/* 400K/800K            */
+#define	DRV_FDHD	5	/* 400K/800K/720K/1440K */
+#define	DRV_HD20	7	/* Apple HD20           */
+
+/* Format types: */
+
+#define	FMT_HD20	0x0001	/*  Apple HD20 */
+#define	FMT_400K	0x0002	/*  400K (GCR) */
+#define	FMT_800K	0x0004	/*  800K (GCR) */
+#define	FMT_720K	0x0008	/*  720K (MFM) */
+#define	FMT_1440K	0x0010	/* 1.44M (MFM) */
+
+#define	FMD_KIND_400K	1
+#define	FMD_KIND_800K	2
+#define	FMD_KIND_720K	3
+#define	FMD_KIND_1440K	1
+
+/* Icon Flags: */
+
+#define	ICON_MEDIA	0x01	/* Have IOP supply media icon */
+#define	ICON_DRIVE	0x01	/* Have IOP supply drive icon */
+
+/* Error codes: */
+
+#define	gcrOnMFMErr	-400	/* GCR (400/800K) on HD media */
+#define	verErr		-84	/* verify failed */
+#define	fmt2Err		-83	/* cant get enough sync during format */
+#define	fmt1Err		-82	/* can't find sector 0 after track format */
+#define	sectNFErr	-81	/* can't find sector */
+#define	seekErr		-80	/* drive error during seek */
+#define	spdAdjErr	-79	/* can't set drive speed */
+#define	twoSideErr	-78	/* drive is single-sided */
+#define	initIWMErr	-77	/* error during initialization */
+#define	tk0badErr	-76	/* track zero is bad */
+#define	cantStepErr	-75	/* drive error during step */
+#define	wrUnderrun	-74	/* write underrun occurred */
+#define	badDBtSlp	-73	/* bad data bitslip marks */
+#define	badDCksum	-72	/* bad data checksum */
+#define	noDtaMkErr	-71	/* can't find data mark */
+#define	badBtSlpErr	-70	/* bad address bitslip marks */
+#define	badCksmErr	-69	/* bad address-mark checksum */
+#define	dataVerErr	-68	/* read-verify failed */
+#define	noAdrMkErr	-67	/* can't find an address mark */
+#define	noNybErr	-66	/* no nybbles? disk is probably degaussed */
+#define	offLinErr	-65	/* no disk in drive */
+#define	noDriveErr	-64	/* drive isn't connected */
+#define	nsDrvErr	-56	/* no such drive */
+#define	paramErr	-50	/* bad positioning information */
+#define	wPrErr		-44	/* write protected */
+#define	openErr		-23	/* already initialized */
+
+#ifndef __ASSEMBLY__
+
+struct swim_drvstatus {
+	__u16	curr_track;	/* Current track number                   */
+	__u8	write_prot;	/* 0x80 if disk is write protected        */
+	__u8	disk_in_drive;	/* 0x01 or 0x02 if a disk is in the drive */
+	__u8	installed;	/* 0x01 if drive installed, 0xFF if not   */
+	__u8	num_sides;	/* 0x80 if two-sided format supported     */
+	__u8	two_sided;	/* 0xff if two-sided format diskette      */
+	__u8	new_interface;	/* 0x00 if old 400K drive, 0xFF if newer  */
+	__u16	errors;		/* Disk error count                       */
+	struct {		/* 32 bits */
+		__u16	reserved;
+		__u16	:4;
+		__u16	external:1;	/* Drive is external        */
+		__u16	scsi:1;		/* Drive is a SCSI drive    */
+		__u16	fixed:1;	/* Drive has fixed media    */
+		__u16	secondary:1;	/* Drive is secondary drive */
+		__u8	type;		/* Drive type               */
+	} info;
+	__u8	mfm_drive;	/* 0xFF if this is an FDHD drive    */
+	__u8	mfm_disk;	/* 0xFF if 720K/1440K (MFM) disk    */
+	__u8	mfm_format;	/* 0x00 if 720K, 0xFF if 1440K      */
+	__u8	ctlr_type;	/* 0x00 if IWM, 0xFF if SWIM        */
+	__u16	curr_format;	/* Current format type              */
+	__u16	allowed_fmt;	/* Allowed format types             */
+	__u32	num_blocks;	/* Number of blocks on disk         */
+	__u8	icon_flags;	/* Icon flags                       */
+	__u8	unusued;
+};
+
+/* Commands issued from the host to the IOP: */
+
+struct swimcmd_init {
+	__u8	code;		/* CMD_INIT */
+	__u8	unusued;
+	__u16	error;
+	__u8	drives[28];	/* drive type list */
+};
+
+struct swimcmd_startpoll {
+	__u8	code;		/* CMD_START_POLL */
+	__u8	unusued;
+	__u16	error;
+};
+
+struct swimcmd_sethfstag {
+	__u8	code;		/* CMD_SETHFSTAG */
+	__u8	unusued;
+	__u16	error;
+	caddr_t	tagbuf;		/* HFS tag buffer address */
+};
+
+struct swimcmd_status {
+	__u8	code;		/* CMD_STATUS */
+	__u8	drive_num;
+	__u16	error;
+	struct swim_drvstatus status;
+};
+
+struct swimcmd_eject {
+	__u8	code;		/* CMD_EJECT */
+	__u8	drive_num;
+	__u16	error;
+	struct swim_drvstatus status;
+};
+
+struct swimcmd_format {
+	__u8	code;		/* CMD_FORMAT */
+	__u8	drive_num;
+	__u16	error;
+	union {
+		struct {
+			__u16 fmt;	   /* format kind                  */
+			__u8  hdrbyte;	   /* fmt byte for hdr (0=default) */
+			__u8  interleave;  /* interleave (0 = default)     */
+			caddr_t	databuf;   /* sector data buff (0=default  */
+			caddr_t	tagbuf;	   /* tag data buffer (0=default)  */
+		} f;
+		struct swim_drvstatus status;
+	} p;
+};
+
+struct swimcmd_fmtverify {
+	__u8	code;		/* CMD_FORMAT_VERIFY */
+	__u8	drive_num;
+	__u16	error;
+};
+
+struct swimcmd_rw {
+	__u8	code;		/* CMD_READ, CMD_WRITE or CMD_READ_VERIFY */
+	__u8	drive_num;
+	__u16	error;
+	caddr_t	buffer;		/* R/W buffer address */
+	__u32	first_block;	/* Starting block     */
+	__u32	num_blocks;	/* Number of blocks   */
+	__u8	tag[12];	/* tag data           */
+};
+
+struct swimcmd_cachectl {
+	__u8	code;		/* CMD_CACHE_CTRL */
+	__u8	unused;
+	__u16	error;
+	__u8	enable;		/* Nonzero to enable cache                */
+	__u8	install;	/* +1 = install, -1 = remove, 0 = neither */
+};
+
+struct swimcmd_tagbufctl {
+	__u8	code;		/* CMD_TAGBUFF_CTRL */
+	__u8	unused;
+	__u16	error;
+	caddr_t	buf;		/* buffer address or 0 to disable */
+};
+
+struct swimcmd_geticon {
+	__u8	code;		/* CMD_GET_ICON */
+	__u8	drive_num;
+	__u16	error;
+	caddr_t	buffer;		/* Nuffer address */
+	__u16	kind;		/* 0 = media icon, 1 = drive icon */
+	__u16	unused;
+	__u16	max_bytes;	/* maximum  byte count */
+};
+
+/* Messages from the SWIM IOP to the host CPU: */
+
+struct swimmsg_status {
+	__u8	code;		/* 1 = insert, 2 = eject, 3 = status changed */
+	__u8	drive_num;
+	__u16	error;
+	struct swim_drvstatus status;
+};
+
+#endif /* __ASSEMBLY__ */
diff -u --recursive --new-file v2.3.16/linux/include/asm-m68k/virtconvert.h linux/include/asm-m68k/virtconvert.h
--- v2.3.16/linux/include/asm-m68k/virtconvert.h	Tue Jan 19 10:58:34 1999
+++ linux/include/asm-m68k/virtconvert.h	Sat Sep  4 13:06:41 1999
@@ -17,9 +17,21 @@
 /*
  * Change virtual addresses to physical addresses and vv.
  */
+#ifndef CONFIG_SUN3
 extern unsigned long mm_vtop(unsigned long addr) __attribute__ ((const));
 extern unsigned long mm_vtop_fallback (unsigned long) __attribute__ ((const));
 extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const));
+#else
+extern inline unsigned long mm_vtop(unsigned long vaddr)
+{
+	return __pa(vaddr);
+}
+
+extern inline unsigned long mm_ptov(unsigned long paddr)
+{
+	return (unsigned long)__va(paddr);
+}
+#endif 
 
 #ifdef CONFIG_SINGLE_MEMORY_CHUNK
 extern inline unsigned long virt_to_phys(volatile void * address)
diff -u --recursive --new-file v2.3.16/linux/include/asm-mips/hardirq.h linux/include/asm-mips/hardirq.h
--- v2.3.16/linux/include/asm-mips/hardirq.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-mips/hardirq.h	Wed Sep  1 14:12:09 1999
@@ -9,7 +9,7 @@
 #ifndef __ASM_MIPS_HARDIRQ_H
 #define __ASM_MIPS_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 extern unsigned int local_irq_count[NR_CPUS];
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-ppc/gemini_serial.h linux/include/asm-ppc/gemini_serial.h
--- v2.3.16/linux/include/asm-ppc/gemini_serial.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/gemini_serial.h	Wed Sep  1 15:34:01 1999
@@ -1,6 +1,7 @@
 #ifndef __ASMPPC_GEMINI_SERIAL_H
 #define __ASMPPC_GEMINI_SERIAL_H
 
+#include <linux/config.h>
 #include <asm/gemini.h>
 
 /* Rate for the 24.576 Mhz clock for the onboard serial chip */
diff -u --recursive --new-file v2.3.16/linux/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- v2.3.16/linux/include/asm-ppc/pmu.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-ppc/pmu.h	Wed Sep  1 15:34:01 1999
@@ -6,7 +6,6 @@
  * Copyright (C) 1998 Paul Mackerras.
  */
 
-#include <linux/config.h>
 /*
  * PMU commands
  */
diff -u --recursive --new-file v2.3.16/linux/include/asm-sh/bugs.h linux/include/asm-sh/bugs.h
--- v2.3.16/linux/include/asm-sh/bugs.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/bugs.h	Wed Sep  1 15:34:01 1999
@@ -12,7 +12,6 @@
  * I don't know of any Super-H bugs yet.
  */
 
-#include <linux/config.h>
 #include <asm/processor.h>
 
 __initfunc(static void check_bugs(void))
diff -u --recursive --new-file v2.3.16/linux/include/asm-sh/elf.h linux/include/asm-sh/elf.h
--- v2.3.16/linux/include/asm-sh/elf.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sh/elf.h	Wed Sep  1 15:34:01 1999
@@ -5,6 +5,7 @@
  * ELF register definitions..
  */
 
+#include <linux/config.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <asm/byteorder.h>
diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc/ap1000/apreg.h linux/include/asm-sparc/ap1000/apreg.h
--- v2.3.16/linux/include/asm-sparc/ap1000/apreg.h	Sun Jan 26 02:07:47 1997
+++ linux/include/asm-sparc/ap1000/apreg.h	Wed Sep  1 14:12:09 1999
@@ -12,7 +12,7 @@
 #include <asm/page.h>
 #include <asm/ap1000/apservice.h>
 #include <asm/ap1000/apbif.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 /*
  * Macros for accessing I/O registers.
diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc/audioio.h linux/include/asm-sparc/audioio.h
--- v2.3.16/linux/include/asm-sparc/audioio.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc/audioio.h	Wed Sep  1 15:34:01 1999
@@ -237,7 +237,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc64/audioio.h linux/include/asm-sparc64/audioio.h
--- v2.3.16/linux/include/asm-sparc64/audioio.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/audioio.h	Wed Sep  1 15:34:02 1999
@@ -237,7 +237,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.3.16/linux/include/asm-sparc64/dma.h	Tue Aug 31 17:29:14 1999
+++ linux/include/asm-sparc64/dma.h	Wed Sep  1 15:34:02 1999
@@ -7,6 +7,7 @@
 #ifndef _ASM_SPARC64_DMA_H
 #define _ASM_SPARC64_DMA_H
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 
diff -u --recursive --new-file v2.3.16/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.3.16/linux/include/asm-sparc64/hardirq.h	Mon Jul 19 13:12:47 1999
+++ linux/include/asm-sparc64/hardirq.h	Wed Sep  1 14:12:09 1999
@@ -6,7 +6,7 @@
 #ifndef __SPARC64_HARDIRQ_H
 #define __SPARC64_HARDIRQ_H
 
-#include <linux/tasks.h>
+#include <linux/threads.h>
 
 #ifndef __SMP__
 extern unsigned int local_irq_count;
diff -u --recursive --new-file v2.3.16/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.3.16/linux/include/linux/blk.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/blk.h	Tue Sep  7 11:29:07 1999
@@ -57,6 +57,7 @@
 extern int ddv_init(void);
 extern int z2_init(void);
 extern int swim3_init(void);
+extern int swimiop_init(void);
 extern int amiga_floppy_init(void);
 extern int atari_floppy_init(void);
 extern int nbd_init(void);
diff -u --recursive --new-file v2.3.16/linux/include/linux/cd1400.h linux/include/linux/cd1400.h
--- v2.3.16/linux/include/linux/cd1400.h	Wed Feb  4 14:52:16 1998
+++ linux/include/linux/cd1400.h	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	cd1400.h  -- cd1400 UART hardware info.
  *
  *	Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	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
diff -u --recursive --new-file v2.3.16/linux/include/linux/cdk.h linux/include/linux/cdk.h
--- v2.3.16/linux/include/linux/cdk.h	Wed Feb  4 14:52:16 1998
+++ linux/include/linux/cdk.h	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	cdk.h  -- CDK interface definitions.
  *
  *	Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	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
diff -u --recursive --new-file v2.3.16/linux/include/linux/comstats.h linux/include/linux/comstats.h
--- v2.3.16/linux/include/linux/comstats.h	Wed Feb  4 14:52:16 1998
+++ linux/include/linux/comstats.h	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	comstats.h  -- Serial Port Stats.
  *
  *	Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	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
diff -u --recursive --new-file v2.3.16/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.3.16/linux/include/linux/fs.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/fs.h	Tue Sep  7 11:28:52 1999
@@ -269,6 +269,7 @@
 #include <linux/hfs_fs_i.h>
 #include <linux/adfs_fs_i.h>
 #include <linux/qnx4_fs_i.h>
+#include <linux/udf_fs_i.h>
 
 /*
  * Attribute flags.  These should be or-ed together to figure out what
@@ -381,6 +382,7 @@
 		struct hfs_inode_info		hfs_i;
 		struct adfs_inode_info		adfs_i;
 		struct qnx4_inode_info		qnx4_i;
+		struct udf_inode_info		udf_i;
 		struct socket			socket_i;
 		void				*generic_ip;
 	} u;
@@ -510,6 +512,7 @@
 #include <linux/hfs_fs_sb.h>
 #include <linux/adfs_fs_sb.h>
 #include <linux/qnx4_fs_sb.h>
+#include <linux/udf_fs_sb.h>
 
 extern struct list_head super_blocks;
 
@@ -554,6 +557,7 @@
 		struct hfs_sb_info	hfs_sb;
 		struct adfs_sb_info	adfs_sb;
 		struct qnx4_sb_info	qnx4_sb;
+		struct udf_sb_info	udf_sb;
 		void			*generic_sbp;
 	} u;
 	/*
diff -u --recursive --new-file v2.3.16/linux/include/linux/i2o.h linux/include/linux/i2o.h
--- v2.3.16/linux/include/linux/i2o.h	Fri Aug  6 11:16:54 1999
+++ linux/include/linux/i2o.h	Thu Sep  2 10:18:33 1999
@@ -169,7 +169,6 @@
 	char dev_name[8];		/* linux /dev name if available */
 };
 
-#ifdef CONFIG_I2O_PCI_MODULE
 /*
  *	Resource data for each PCI I2O controller
  */	 	
@@ -177,7 +176,7 @@
 {
 	int irq;
 };
-#endif
+
 
 /*
  *	Each I2O controller has one of these objects
diff -u --recursive --new-file v2.3.16/linux/include/linux/if_arp.h linux/include/linux/if_arp.h
--- v2.3.16/linux/include/linux/if_arp.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/if_arp.h	Tue Sep  7 11:29:50 1999
@@ -67,7 +67,7 @@
 #define ARPHRD_HIPPI	780		/* High Performance Parallel Interface */
 #define ARPHRD_ASH	781		/* Nexus 64Mbps Ash		*/
 #define ARPHRD_ECONET	782		/* Acorn Econet			*/
-#define ARPHRD_IRDA 	783		/* Linux/IR			*/
+#define ARPHRD_IRDA 	783		/* Linux-IrDA			*/
 /* ARP works differently on different FC media .. so  */
 #define ARPHRD_FCPP	784		/* Point to point fibrechanel	*/
 #define ARPHRD_FCAL	785		/* Fibrechannel arbitrated loop */
diff -u --recursive --new-file v2.3.16/linux/include/linux/if_ether.h linux/include/linux/if_ether.h
--- v2.3.16/linux/include/linux/if_ether.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/if_ether.h	Tue Sep  7 10:14:37 1999
@@ -74,7 +74,7 @@
 #define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
 #define ETH_P_MOBITEX	0x0015		/* Mobitex (kaz@cafe.net)	*/
 #define ETH_P_CONTROL	0x0016		/* Card specific control frames */
-#define ETH_P_IRDA	0x0017		/* Linux/IR			*/
+#define ETH_P_IRDA	0x0017		/* Linux-IrDA			*/
 #define ETH_P_ECONET	0x0018		/* Acorn Econet			*/
 
 /*
diff -u --recursive --new-file v2.3.16/linux/include/linux/ioport.h linux/include/linux/ioport.h
--- v2.3.16/linux/include/linux/ioport.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/ioport.h	Fri Sep  3 13:17:15 1999
@@ -87,11 +87,16 @@
 
 /* Convenience shorthand with allocation */
 #define request_region(start,n,name)	__request_region(&ioport_resource, (start), (n), (name))
+#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
+
 extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name);
 
 /* Compatibility cruft */
 #define check_region(start,n)	__check_region(&ioport_resource, (start), (n))
 #define release_region(start,n)	__release_region(&ioport_resource, (start), (n))
+#define check_mem_region(start,n)	__check_region(&iomem_resource, (start), (n))
+#define release_mem_region(start,n)	__release_region(&iomem_resource, (start), (n))
+
 extern int __check_region(struct resource *, unsigned long, unsigned long);
 extern void __release_region(struct resource *, unsigned long, unsigned long);
 
diff -u --recursive --new-file v2.3.16/linux/include/linux/istallion.h linux/include/linux/istallion.h
--- v2.3.16/linux/include/linux/istallion.h	Sat May 15 15:05:37 1999
+++ linux/include/linux/istallion.h	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	istallion.h  -- stallion intelligent multiport serial driver.
  *
  *	Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	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
@@ -70,9 +70,15 @@
 	long			pgrp;
 	unsigned int		rxmarkmsk;
 	struct tty_struct	*tty;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+	struct wait_queue	*raw_wait;
+#else
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
 	wait_queue_head_t	raw_wait;
+#endif
 	struct tq_struct	tqhangup;
 	struct termios		normaltermios;
 	struct termios		callouttermios;
diff -u --recursive --new-file v2.3.16/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.3.16/linux/include/linux/kernel.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/kernel.h	Tue Sep  7 10:14:37 1999
@@ -91,11 +91,12 @@
 	unsigned long freeram;		/* Available memory size */
 	unsigned long sharedram;	/* Amount of shared memory */
 	unsigned long bufferram;	/* Memory used by buffers */
-	unsigned long totalbig;		/* Total big memory size */
-	unsigned long freebig;		/* Available big memory size */
 	unsigned long totalswap;	/* Total swap space size */
 	unsigned long freeswap;		/* swap space still available */
 	unsigned short procs;		/* Number of current processes */
+	unsigned long totalbig;		/* Total big memory size */
+	unsigned long freebig;		/* Available big memory size */
+	char _f[22-2*sizeof(long)];	/* Padding: libc5 uses this.. */
 };
 
 #endif
diff -u --recursive --new-file v2.3.16/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.3.16/linux/include/linux/mm.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/mm.h	Tue Sep  7 11:28:52 1999
@@ -57,7 +57,7 @@
 	struct vm_operations_struct * vm_ops;
 	unsigned long vm_offset;
 	struct file * vm_file;
-	unsigned long vm_pte;			/* shared mem */
+	void * vm_private_data;		/* was vm_pte (shared mem) */
 };
 
 /*
diff -u --recursive --new-file v2.3.16/linux/include/linux/nubus.h linux/include/linux/nubus.h
--- v2.3.16/linux/include/linux/nubus.h	Sat Mar 21 11:06:51 1998
+++ linux/include/linux/nubus.h	Sat Sep  4 13:10:30 1999
@@ -1,96 +1,322 @@
+/*
+  nubus.h: various definitions and prototypes for NuBus drivers to use.
 
-struct nubus_slot
-{
-	int slot_flags;
-#define NUBUS_DEVICE_PRESENT	1
-#define NUBUS_DEVICE_ACTIVE	2
-#define NUBUS_DEVICE_IRQ	4
-	__u32 slot_directory;
-	__u32 slot_dlength;
-	__u32 slot_crc;
-	__u8  slot_rev;
-	__u8  slot_format;
-	__u8  slot_lanes;
-	/*
-	 *	Stuff we pulled from the directory
-	 */
-	__u32  slot_dirbase;
-	__u32  slot_thisdir;
-	char   slot_vendor[64];
-	char   slot_cardname[64];
+  Originally written by Alan Cox.
+
+  Hacked to death by C. Scott Ananian and David Huggins-Daines.
+  
+  Some of the constants in here are from the corresponding
+  NetBSD/OpenBSD header file, by Allen Briggs.  We figured out the
+  rest of them on our own. */
+
+#ifndef LINUX_NUBUS_H
+#define LINUX_NUBUS_H
+
+enum nubus_category {
+	NUBUS_CAT_BOARD          = 0x0001,
+	NUBUS_CAT_DISPLAY        = 0x0003,
+	NUBUS_CAT_NETWORK        = 0x0004,
+	NUBUS_CAT_COMMUNICATIONS = 0x0006,
+	NUBUS_CAT_FONT           = 0x0009,
+	NUBUS_CAT_CPU            = 0x000A,
+	/* For lack of a better name */
+	NUBUS_CAT_DUODOCK        = 0x0020
 };
 
-struct nbnamevec 
-{
-	char *name;
-	int id;
+enum nubus_type_network {
+	NUBUS_TYPE_ETHERNET = 0x0001,
+	NUBUS_TYPE_RS232    = 0x0002
+};
+
+enum nubus_type_display {
+	NUBUS_TYPE_VIDEO = 0x0001
+};
+
+enum nubus_type_cpu {
+	NUBUS_TYPE_68020 = 0x0003,
+	NUBUS_TYPE_68030 = 0x0004,
+	NUBUS_TYPE_68040 = 0x0005
+};
+
+/* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
+ *  68030 motherboards: <10,4,0,24>
+ *  68040 motherboards: <10,5,0,24>
+ *  DuoDock Plus: <32,1,1,2>
+ *
+ *  Toby Frame Buffer card: <3,1,1,1>
+ *  RBV built-in video (IIci): <3,1,1,24>
+ *  Valkyrie built-in video (Q630): <3,1,1,46>
+ *  Macintosh Display Card: <3,1,1,25>
+ *  Sonora built-in video (P460): <3,1,1,34>
+ *  Jet framebuffer (DuoDock Plus): <3,1,1,41>
+ *
+ *  SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272>
+ *  SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271>
+ *  Sonic Systems Ethernet A-Series Card: <4,1,268,256>
+ *  Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision)
+ *   ROM on the above card: <2,1,0,0>
+ *  Cabletron ethernet card: <4,1,1,265>
+ *  Farallon ethernet card: <4,1,268,256> (identical to Sonic Systems card)
+ *  Kinetics EtherPort IIN: <4,1,259,262>
+ *  API Engineering EtherRun_LCa PDS enet card: <4,1,282,256>
+ *
+ *  Add your devices to the list!  You can obtain the "Slots" utility
+ *  from Apple's FTP site at:
+ *  ftp://dev.apple.com/devworld/Tool_Chest/Devices_-_Hardware/NuBus_Slot_Manager/
+ *
+ *  Alternately, TattleTech can be found at any Info-Mac mirror site.  
+ *  or from its distribution site: ftp://ftp.decismkr.com/dms
+ */
+
+/* DrSW: Uniquely identifies the software interface to a board.  This
+   is usually the one you want to look at when writing a driver.  It's
+   not as useful as you think, though, because as we should know by
+   now (duh), "Apple Compatible" can mean a lot of things... */
+
+/* Add known DrSW values here */
+enum nubus_drsw {
+	/* NUBUS_CAT_DISPLAY */
+	NUBUS_DRSW_APPLE       = 0x0001,
+	NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
+	
+	/* NUBUS_CAT_NETWORK */
+	NUBUS_DRSW_CABLETRON        = 0x0001,
+	NUBUS_DRSW_SONIC_LC         = 0x0001,
+	NUBUS_DRSW_KINETICS         = 0x0103,
+	NUBUS_DRSW_ASANTE           = 0x0104,
+	NUBUS_DRSW_DAYNA            = 0x010b,
+	NUBUS_DRSW_FARALLON         = 0x010c,
+	NUBUS_DRSW_APPLE_SN         = 0x010f,
+	NUBUS_DRSW_FOCUS            = 0x011a,
+	NUBUS_DRSW_ASANTE_CS        = 0x011d, /* use asante SMC9194 driver */
+
+	/* NUBUS_CAT_CPU */
+	NUBUS_DRSW_NONE        = 0x0000,
+};
+
+/* DrHW: Uniquely identifies the hardware interface to a board (or at
+   least, it should...  some video cards are known to incorrectly
+   identify themselves as Toby cards) */
+
+/* Add known DrHW values here */
+enum nubus_drhw {
+	/* NUBUS_CAT_DISPLAY */
+	NUBUS_DRHW_APPLE_TFB	= 0x0001, /* Toby frame buffer card */
+	NUBUS_DRHW_APPLE_RBV1   = 0x0018, /* IIci RBV video */
+	NUBUS_DRHW_APPLE_MDC    = 0x0019, /* Macintosh Display Card */
+	NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
+	NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
+	NUBUS_DRHW_APPLE_JET =    0x0029, /* Jet framebuffer (DuoDock) */
+	
+	/* NUBUS_CAT_NETWORK */
+	NUBUS_DRHW_INTERLAN     = 0x0100,
+	NUBUS_DRHW_SMC9194      = 0x0101,
+	NUBUS_DRHW_KINETICS     = 0x0106,
+	NUBUS_DRHW_CABLETRON    = 0x0109,
+	NUBUS_DRHW_ASANTE_LC    = 0x010f,
+	NUBUS_DRHW_SONIC        = 0x0110,
+};
+
+/* Resource IDs: These are the identifiers for the various weird and
+   wonderful tidbits of information that may or may not reside in the
+   NuBus ROM directory. */
+enum nubus_res_id {
+	NUBUS_RESID_TYPE         = 0x0001,
+	NUBUS_RESID_NAME         = 0x0002,
+	NUBUS_RESID_ICON         = 0x0003,
+	NUBUS_RESID_DRVRDIR      = 0x0004,
+	NUBUS_RESID_LOADREC      = 0x0005,
+	NUBUS_RESID_BOOTREC      = 0x0006,
+	NUBUS_RESID_FLAGS        = 0x0007,
+	NUBUS_RESID_HWDEVID      = 0x0008,
+	NUBUS_RESID_MINOR_BASEOS = 0x000a,
+	NUBUS_RESID_MINOR_LENGTH = 0x000b,
+	NUBUS_RESID_MAJOR_BASEOS = 0x000c,
+	NUBUS_RESID_MAJOR_LENGTH = 0x000d,
+	NUBUS_RESID_CICN         = 0x000f,
+	NUBUS_RESID_ICL8         = 0x0010,
+	NUBUS_RESID_ICL4         = 0x0011,
+};
+
+/* Category-specific resources. */
+enum nubus_board_res_id {
+	NUBUS_RESID_BOARDID	 = 0x0020,
+	NUBUS_RESID_PRAMINITDATA = 0x0021,
+	NUBUS_RESID_PRIMARYINIT	 = 0x0022,
+	NUBUS_RESID_TIMEOUTCONST = 0x0023,
+	NUBUS_RESID_VENDORINFO	 = 0x0024,
+	NUBUS_RESID_BOARDFLAGS	 = 0x0025,
+	NUBUS_RESID_SECONDINIT	 = 0x0026,
+
+	/* Not sure why Apple put these next two in here */
+	NUBUS_RESID_VIDNAMES = 0x0041,
+	NUBUS_RESID_VIDMODES = 0x007e
+};
+
+/* Fields within the vendor info directory */
+enum nubus_vendor_res_id {
+	NUBUS_RESID_VEND_ID     = 0x0001,
+	NUBUS_RESID_VEND_SERIAL = 0x0002,
+	NUBUS_RESID_VEND_REV    = 0x0003,
+	NUBUS_RESID_VEND_PART   = 0x0004,
+	NUBUS_RESID_VEND_DATE   = 0x0005
+};
+
+enum nubus_net_res_id {
+	NUBUS_RESID_MAC_ADDRESS  = 0x0080
+};
+
+enum nubus_cpu_res_id {
+	NUBUS_RESID_MEMINFO      = 0x0081,
+	NUBUS_RESID_ROMINFO      = 0x0082
+};
+
+enum nubus_display_res_id {
+	NUBUS_RESID_GAMMADIR	= 0x0040,
+	NUBUS_RESID_FIRSTMODE	= 0x0080,
+	NUBUS_RESID_SECONDMODE	= 0x0081,
+	NUBUS_RESID_THIRDMODE	= 0x0082,
+	NUBUS_RESID_FOURTHMODE	= 0x0083,
+	NUBUS_RESID_FIFTHMODE	= 0x0084,
+	NUBUS_RESID_SIXTHMODE	= 0x0085
 };
 
 struct nubus_dir
 {
 	unsigned char *base;
-	int length;
-	int count;
+	unsigned char *ptr;
+	int done;
 	int mask;
 };
 
 struct nubus_dirent
 {
+	unsigned char *base;
 	unsigned char type;
-	int value;	/* Actually 24bits used */
+	__u32 data;	/* Actually 24bits used */
 	int mask;
-	int base;	/* For dirptr function */
 };
 
-struct nubus_type
-{
-	__u16 category;
-	__u16 type;
-	__u16 DrHW;
-	__u16 DrSW;
-};
-
-#define NUBUS_CAT_BOARD			0x0001
-#define NUBUS_CAT_DISPLAY		0x0003
-#define NUBUS_CAT_NETWORK		0x0004
-#define NUBUS_CAT_COMMUNICATIONS	0x0006
-#define NUBUS_CAT_FONT			0x0009
-#define NUBUS_CAT_CPU			0x000A
-
-#define RES_ID_TYPE		0x0001
-#define RES_ID_NAME		0x0002
-#define RES_ID_BOARD_DIR	0x0001
-#define RES_ID_FLAGS		0x0007
-
-struct nubus_device_specifier
-{
-	int (*setup)(struct nubus_device_specifier *, int slot, struct nubus_type *);
-	struct nubus_device_specifier *next;
+struct nubus_board {
+	struct nubus_board* next;
+	struct nubus_dev* first_dev;
+	
+        /* Only 9-E actually exist, though 0-8 are also theoretically
+	   possible, and 0 is a special case which represents the
+	   motherboard and onboard peripherals (Ethernet, video) */
+	int slot;
+	/* For slot 0, this is bogus. */
+	char name[64];
+
+	/* Format block */
+	unsigned char* fblock;
+	/* Root directory (does *not* always equal fblock + doffset!) */
+	unsigned char* directory;
+	
+	unsigned long slot_addr;
+	/* Offset to root directory (sometimes) */
+	unsigned long doffset;
+	/* Length over which to compute the crc */
+	unsigned long rom_length;
+	/* Completely useless most of the time */
+	unsigned long crc;
+	unsigned char rev;
+	unsigned char format;
+	unsigned char lanes;
 };
 
+struct nubus_dev {
+	/* Next link in device list */
+	struct nubus_dev* next;
+	/* Directory entry in /proc/bus/nubus */
+	struct proc_dir_entry* procdir;
+
+	/* The functional resource ID of this device */
+	unsigned char resid;
+	/* These are mostly here for convenience; we could always read
+	   them from the ROMs if we wanted to */
+	unsigned short category;
+	unsigned short type;
+	unsigned short dr_sw;
+	unsigned short dr_hw;
+	/* This is the device's name rather than the board's.
+	   Sometimes they are different.  Usually the board name is
+	   more correct. */
+	char name[64];
+	/* MacOS driver (I kid you not) */
+	unsigned char* driver;
+	/* Actually this is an offset */
+	unsigned long iobase;
+	unsigned long iosize;
+	unsigned char flags, hwdevid;
+	
+	/* Functional directory */
+	unsigned char* directory;
+	/* Much of our info comes from here */
+	struct nubus_board* board;
+};
 
-extern void register_nubus_device(struct nubus_device_specifier *nb);
-extern void unregister_nubus_device(struct nubus_device_specifier *nb);
+/* This is all NuBus devices (used to find devices later on) */
+extern struct nubus_dev* nubus_devices;
+/* This is all NuBus cards */
+extern struct nubus_board* nubus_boards;
 
-extern struct nubus_dir *nubus_openrootdir(int slot);
-extern struct nubus_dir *nubus_opensubdir(struct nubus_dirent *d);
-extern void nubus_closedir(struct nubus_dir *);
-extern struct nubus_dirent *nubus_readdir(struct nubus_dir *);
-extern unsigned char *nubus_dirptr(struct nubus_dirent *d);
-extern void nubus_strncpy(int slot, void *to, unsigned char *p, int len);
-extern void nubus_memcpy(int slot, void *to, unsigned char *p, int len);
+/* Generic NuBus interface functions, modelled after the PCI interface */
 extern void nubus_init(void);
-extern void nubus_sweep_video(void);
-extern int nubus_ethernet_addr(int slot, unsigned char *addr);
+void nubus_scan_bus(void);
+extern void nubus_proc_init(void);
+int get_nubus_list(char *buf);
+int nubus_proc_attach_device(struct nubus_dev *dev);
+int nubus_proc_detach_device(struct nubus_dev *dev);
+/* If we need more precision we can add some more of these */
+struct nubus_dev* nubus_find_device(unsigned short category,
+				    unsigned short type,
+				    unsigned short dr_hw,
+				    unsigned short dr_sw,
+				    const struct nubus_dev* from);
+struct nubus_dev* nubus_find_type(unsigned short category,
+				  unsigned short type,
+				  const struct nubus_dev* from);
+/* Might have more than one device in a slot, you know... */
+struct nubus_dev* nubus_find_slot(unsigned int slot,
+				  const struct nubus_dev* from);
+
+/* These are somewhat more NuBus-specific.  They all return 0 for
+   success and -1 for failure, as you'd expect. */
+
+/* The root directory which contains the board and functional
+   directories */
+int nubus_get_root_dir(const struct nubus_board* board,
+		       struct nubus_dir* dir);
+/* The board directory */
+int nubus_get_board_dir(const struct nubus_board* board,
+			struct nubus_dir* dir);
+/* The functional directory */
+int nubus_get_func_dir(const struct nubus_dev* dev,
+		       struct nubus_dir* dir);
+
+/* These work on any directory gotten via the above */
+int nubus_readdir(struct nubus_dir* dir,
+		  struct nubus_dirent* ent);
+int nubus_find_rsrc(struct nubus_dir* dir,
+		    unsigned char rsrc_type,
+		    struct nubus_dirent* ent);
+int nubus_rewinddir(struct nubus_dir* dir);
+
+/* Things to do with directory entries */
+int nubus_get_subdir(const struct nubus_dirent* ent,
+		     struct nubus_dir* dir);
+void nubus_get_rsrc_mem(void* dest,
+			const struct nubus_dirent *dirent,
+			int len);
+void nubus_get_rsrc_str(void* dest,
+			const struct nubus_dirent *dirent,
+			int maxlen);
 
-extern __inline void *nubus_slot_addr(int slot)
+/* We'd like to get rid of this eventually.  Only daynaport.c uses it now. */
+extern inline void *nubus_slot_addr(int slot)
 {
 	return (void *)(0xF0000000|(slot<<24));
 }
 
-extern int nubus_hwreg_present(volatile void *ptr);
-
-extern void nubus_init_via(void);
-extern int nubus_free_irq(int slot);
-extern int nubus_request_irq(int slot, void *dev_id, void (*handler)(int,void *,struct pt_regs *));
-
+#endif LINUX_NUBUS_H
diff -u --recursive --new-file v2.3.16/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.3.16/linux/include/linux/pagemap.h	Wed Aug 18 16:43:44 1999
+++ linux/include/linux/pagemap.h	Tue Sep  7 11:28:53 1999
@@ -108,6 +108,4 @@
 		___wait_on_page(page);
 }
 
-extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
-
 #endif
diff -u --recursive --new-file v2.3.16/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.3.16/linux/include/linux/pci.h	Tue Aug 31 17:29:14 1999
+++ linux/include/linux/pci.h	Tue Sep  7 11:28:52 1999
@@ -654,6 +654,12 @@
 #define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
 #define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
 
+#define PCI_VENDOR_ID_MYLEX		0x1069
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V2	0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V3	0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V4	0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960P_V5	0x0020
+
 #define PCI_VENDOR_ID_PICOP		0x1066
 #define PCI_DEVICE_ID_PICOP_PT86C52X	0x0001
 #define PCI_DEVICE_ID_PICOP_PT80C524	0x8002
@@ -1341,6 +1347,10 @@
 #define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
 #define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
 
+#define PCI_VENDOR_ID_INTERPHASE		0x107e
+#define PCI_DEVICE_ID_INTERPHASE_5526	0x0004
+#define PCI_DEVICE_ID_INTERPHASE_55x6	0x0005
+
 /*
  * The PCI interface treats multi-function devices as independent
  * devices.  The slot/function address of each device is encoded
@@ -1478,7 +1488,9 @@
 void pcibios_init(void);
 void pcibios_fixup_bus(struct pci_bus *);
 char *pcibios_setup (char *str);
-int pcibios_assign_resource(struct pci_dev *, int i);
+void pcibios_update_resource(struct pci_dev *, struct resource *,
+			     struct resource *, int);
+void pcibios_update_irq(struct pci_dev *, int irq);
 
 
 /* Backward compatibility, don't use in new code! */
@@ -1519,6 +1531,12 @@
 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);
 int pci_find_capability (struct pci_dev *dev, int cap);
+
+int pci_claim_resource(struct pci_dev *, int);
+void pci_assign_unassigned_resources(u32 min_io, u32 min_mem);
+void pci_set_bus_ranges(void);
+void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
+		    int (*)(struct pci_dev *, u8, u8));
 
 #define PCI_ANY_ID (~0)
 
diff -u --recursive --new-file v2.3.16/linux/include/linux/personality.h linux/include/linux/personality.h
--- v2.3.16/linux/include/linux/personality.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/personality.h	Sat Sep  4 13:06:08 1999
@@ -28,9 +28,10 @@
 #define PER_IRIXN32             (0x000a | STICKY_TIMEOUTS) /* IRIX6 new 32-bit */
 #define PER_IRIX64              (0x000b | STICKY_TIMEOUTS) /* IRIX6 64-bit     */
 #define PER_RISCOS		(0x000c)
+#define PER_SOLARIS		(0x000d | STICKY_TIMEOUTS)
 
 /* Prototype for an lcall7 syscall handler. */
-typedef void (*lcall7_func)(struct pt_regs *);
+typedef void (*lcall7_func)(int, struct pt_regs *);
 
 
 /* Description of an execution domain - personality range supported,
diff -u --recursive --new-file v2.3.16/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.3.16/linux/include/linux/proc_fs.h	Thu Aug 26 13:05:41 1999
+++ linux/include/linux/proc_fs.h	Tue Sep  7 11:28:53 1999
@@ -23,6 +23,7 @@
 	PROC_PCI,
 	PROC_MCA,
 	PROC_NUBUS,
+	PROC_MAC_VIA,
 	PROC_SELF,	/* will change inode # */
 	PROC_NET,
         PROC_SCSI,
@@ -234,6 +235,8 @@
 	PROC_BUS_ZORRO,
 	PROC_BUS_ZORRO_DEVICES,
 	PROC_BUS_ECARD_DEVICES,
+	PROC_BUS_NUBUS,
+	PROC_BUS_NUBUS_DEVICES,
 	PROC_BUS_LAST
 };
 
diff -u --recursive --new-file v2.3.16/linux/include/linux/serialP.h linux/include/linux/serialP.h
--- v2.3.16/linux/include/linux/serialP.h	Tue Aug 31 17:29:15 1999
+++ linux/include/linux/serialP.h	Tue Sep  7 11:28:52 1999
@@ -19,6 +19,7 @@
  * For definitions of the flags field, see tty.h
  */
 
+#include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 #include <linux/wait.h>
@@ -146,6 +147,7 @@
 #define ALPHA_KLUDGE_MCR 0
 #endif
 
+#ifdef CONFIG_PCI
 /*
  * Structures and definitions for PCI support
  */
@@ -170,6 +172,7 @@
 
 #ifndef PCI_ANY_ID
 #define PCI_ANY_ID (~0)
+#endif
 #endif
 
 #define SPCI_FL_BASE_MASK	0x0007
diff -u --recursive --new-file v2.3.16/linux/include/linux/stallion.h linux/include/linux/stallion.h
--- v2.3.16/linux/include/linux/stallion.h	Sat May 15 15:05:37 1999
+++ linux/include/linux/stallion.h	Thu Sep  2 11:22:40 1999
@@ -4,7 +4,7 @@
  *	stallion.h  -- stallion multiport serial driver.
  *
  *	Copyright (C) 1996-1998  Stallion Technologies (support@stallion.oz.au).
- *	Copyright (C) 1994-1996  Greg Ungerer (gerg@stallion.oz.au).
+ *	Copyright (C) 1994-1996  Greg Ungerer.
  *
  *	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
@@ -95,8 +95,13 @@
 	unsigned long		hwid;
 	void			*uartp;
 	struct tty_struct	*tty;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+#else
 	wait_queue_head_t	open_wait;
 	wait_queue_head_t	close_wait;
+#endif
 	struct termios		normaltermios;
 	struct termios		callouttermios;
 	struct tq_struct	tqueue;
diff -u --recursive --new-file v2.3.16/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.3.16/linux/include/linux/tty.h	Wed Aug 18 16:43:35 1999
+++ linux/include/linux/tty.h	Tue Sep  7 11:28:52 1999
@@ -344,6 +344,7 @@
 extern int lp_init(void);
 extern int pty_init(void);
 extern int tty_init(void);
+extern int ip2_init(void);
 extern int pcxe_init(void);
 extern int pc_init(void);
 extern int vcs_init(void);
diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_167.h linux/include/linux/udf_167.h
--- v2.3.16/linux/include/linux/udf_167.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/udf_167.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,778 @@
+#if !defined(_LINUX_UDF_167_H)
+#define _LINUX_UDF_167_H
+/*
+ * udf_167.h
+ *
+ * DESCRIPTION
+ *	Definitions from the ECMA 167 standard.
+ *	http://www.ecma.ch/
+ *
+ *	These abbreviations are used to keep the symbols short:
+ *		Alloc	Allocation
+ *		App	Application
+ *		Attr	Attribute
+ *		Char	Characters
+ *		Desc	Descriptor
+ *		Descs	Descriptors
+ *		Ext	Extent
+ *		Ident	Identifier
+ *		Imp	Implementation
+ *		Lvl	Level
+ *		Max	Maximum
+ *		Num	Number
+ *		Ptr	Pointer
+ *		Seq	Sequence
+ *		Std	Standard
+ *		Struct	Structure
+ *		Vol	Volume
+ *	The symbols are otherwise identical to the standard, and the
+ *	sections of the standard to refer to are indicated.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ * HISTORY
+ *	July 12, 1997 - Andrew E. Mileski
+ *	Adapted from the ECMA-167 standard.
+ *
+ * 10/2/98 dgb	Adaptation
+ * 10/4/98 	Changes by HJA Sandkuyl
+ * 10/7/98	Changed FILE_EXISTENCE to FILE_HIDDEN, per UDF 2.0 spec
+ * 11/26/98	Modifed some entries for UDF 1.5/2.0
+ * 11/26/98 bf  Fixed typos, non-linux types, more structures
+ * 12/5/98 dgb  Adjusted structure and content of include files.
+ */
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#define Uint8	__u8
+#define Uint16	__u16
+#define Uint32	__u32
+#define Uint64	__u64
+typedef Uint8	dstring;
+#else
+#define Uint8	unsigned char
+#define Uint16	unsigned short
+#define Uint32	unsigned int
+#define Uint64	unsigned long long
+typedef Uint8	dstring;
+#endif
+
+/* make sure all structures are packed! */
+#pragma pack(1)
+
+/* CS0 Charspec (ECMA 167 1/7.2.1) */
+typedef struct {
+	Uint8 charSetType;
+	Uint8 charSetInfo[63];
+} charspec;
+
+/* Timestamp (ECMA 167 1/7.3) */
+typedef struct {
+	Uint16 typeAndTimezone;
+	Uint16 year;
+	Uint8 month;
+	Uint8 day;
+	Uint8 hour;
+	Uint8 minute;
+	Uint8 second;
+	Uint8 centiseconds;
+	Uint8 hundredsOfMicroseconds;
+	Uint8 microseconds;
+} timestamp;
+
+/* Timestamp types (ECMA 167 1/7.3.1) */
+#define TIMESTAMP_TYPE_CUT		0x0000U
+#define TIMESTAMP_TYPE_LOCAL		0x0001U
+#define TIMESTAMP_TYPE_AGREEMENT	0x0002U
+
+/* Entity Identifier (ECMA 167 1/7.4) */
+typedef struct {
+	Uint8 flags;
+	Uint8 ident[23];
+	Uint8 identSuffix[8];
+} EntityID;
+#define regid EntityID
+
+/* Entity identifier flags (ECMA 167 1/7.4.1) */
+#define ENTITYID_FLAGS_DIRTY		0x01U
+#define ENTITYID_FLAGS_PROTECTED	0x02U
+
+/* Volume Structure Descriptor (ECMA 167 2/9.1) */
+#define STD_ID_LEN	5
+struct VolStructDesc {
+	Uint8 structType;
+	Uint8 stdIdent[STD_ID_LEN];
+	Uint8 structVersion;
+	Uint8 structData[2041];
+};
+
+/* Std structure identifiers (ECMA 167 2/9.1.2) */
+#define STD_ID_BEA01	"BEA01"
+#define STD_ID_BOOT2	"BOOT2"
+#define STD_ID_CD001	"CD001"
+#define STD_ID_CDW02	"CDW02"
+#define STD_ID_NSR02	"NSR02"
+#define STD_ID_NSR03	"NSR03"
+#define STD_ID_TEA01	"TEA01"
+
+/* Beginning Extended Area Descriptor (ECMA 167 2/9.2) */
+struct BeginningExtendedAreaDesc {
+	Uint8 structType;
+	Uint8 stdIdent[STD_ID_LEN];
+	Uint8 structVersion;
+	Uint8 structData[2041];
+};
+
+/* Terminating Extended Area Descriptor (ECMA 167 2/9.3) */
+struct TerminatingExtendedAreaDesc {
+	Uint8 structType;
+	Uint8 stdIdent[STD_ID_LEN];
+	Uint8 structVersion;
+	Uint8 structData[2041];
+};
+
+/* Boot Descriptor (ECMA 167 2/9.4) */
+struct BootDesc {
+	Uint8 structType;
+	Uint8 stdIdent[STD_ID_LEN];
+	Uint8 structVersion;
+	Uint8 reserved1;
+	EntityID architectureType;
+	EntityID bootIdent;
+	Uint32 bootExtLocation;
+	Uint32 bootExtLength;
+	Uint64 loadAddress;
+	Uint64 startAddress;
+	timestamp descCreationDateAndTime;
+	Uint16 flags;
+	Uint8 reserved2[32];
+	Uint8 bootUse[1906];
+};
+
+/* Boot flags (ECMA 167 2/9.4.12) */
+#define BOOT_FLAGS_ERASE	1
+
+/* Extent Descriptor (ECMA 167 3/7.1) */
+typedef struct {
+	Uint32 extLength;
+	Uint32 extLocation;
+} extent_ad;
+
+/* Descriptor Tag (ECMA 167 3/7.2) */
+typedef struct {
+	Uint16 tagIdent;
+	Uint16 descVersion;
+	Uint8 tagChecksum;
+	Uint8 reserved;
+	Uint16 tagSerialNum;
+	Uint16 descCRC;
+	Uint16 descCRCLength;
+	Uint32 tagLocation;
+} tag;
+
+/* Tag Identifiers (ECMA 167 3/7.2.1) */
+#define TID_UNUSED_DESC			0x0000U
+#define TID_PRIMARY_VOL_DESC		0x0001U
+#define TID_ANCHOR_VOL_DESC_PTR		0x0002U
+#define TID_VOL_DESC_PTR		0x0003U
+#define TID_IMP_USE_VOL_DESC		0x0004U
+#define TID_PARTITION_DESC		0x0005U
+#define TID_LOGICAL_VOL_DESC		0x0006U
+#define TID_UNALLOC_SPACE_DESC		0x0007U
+#define TID_TERMINATING_DESC		0x0008U
+#define TID_LOGICAL_VOL_INTEGRITY_DESC	0x0009U
+
+/* Tag Identifiers (ECMA 167 4/7.2.1) */
+#define TID_FILE_SET_DESC		0x0100U
+#define TID_FILE_IDENT_DESC		0x0101U
+#define TID_ALLOC_EXTENT_DESC		0x0102U
+#define TID_INDIRECT_ENTRY		0x0103U
+#define TID_TERMINAL_ENTRY		0x0104U
+#define TID_FILE_ENTRY			0x0105U
+#define TID_EXTENDED_ATTRE_HEADER_DESC	0x0106U
+#define TID_UNALLOCATED_SPACE_ENTRY	0x0107U
+#define TID_SPACE_BITMAP_DESC		0x0108U
+#define TID_PARTITION_INTEGRITY_ENTRY	0x0109U
+#define TID_EXTENDED_FILE_ENTRY		0x010AU
+
+/* NSR Descriptor (ECMA 167 3/9.1) */
+struct NSRDesc {
+	Uint8 structType;
+	Uint8 stdIdent[STD_ID_LEN];
+	Uint8 structVersion;
+	Uint8 reserved;
+	Uint8 structData[2040];
+};
+	
+/* Primary Volume Descriptor (ECMA 167 3/10.1) */
+struct PrimaryVolDesc {
+	tag descTag;
+	Uint32 volDescSeqNum;
+	Uint32 primaryVolDescNum;
+	dstring volIdent[32];
+	Uint16 volSeqNum;
+	Uint16 maxVolSeqNum;
+	Uint16 interchangeLvl;
+	Uint16 maxInterchangeLvl;
+	Uint32 charSetList;
+	Uint32 maxCharSetList;
+	dstring volSetIdent[128];
+	charspec descCharSet;
+	charspec explanatoryCharSet;
+	extent_ad volAbstract;
+	extent_ad volCopyright;
+	EntityID appIdent;
+	timestamp recordingDateAndTime;
+	EntityID impIdent;
+	Uint8 impUse[64];
+	Uint32 predecessorVolDescSeqLocation;
+	Uint16 flags;
+	Uint8 reserved[22];
+};
+
+/* Primary volume descriptor flags (ECMA 167 3/10.1.21) */
+#define VOL_SET_IDENT	1
+
+/* Anchor Volume Descriptor Pointer (ECMA 167 3/10.2) */
+struct AnchorVolDescPtr {
+	tag descTag;
+	extent_ad mainVolDescSeqExt;
+	extent_ad reserveVolDescSeqExt;
+	Uint8 reserved[480];
+};
+
+/* Volume Descriptor Pointer (ECMA 167 3/10.3) */
+struct VolDescPtr {
+	tag descTag;
+	Uint32 volDescSeqNum;
+	extent_ad nextVolDescSeqExt;
+	Uint8 reserved[484];
+};
+
+/* Implementation Use Volume Descriptor (ECMA 167 3/10.4) */
+struct ImpUseVolDesc {
+	tag descTag;
+	Uint32 volDescSeqNum;
+	EntityID impIdent;
+	Uint8 impUse[460];
+};
+
+/* Partition Descriptor (ECMA 167 3/10.5) */
+struct PartitionDesc {
+	tag descTag;
+	Uint32 volDescSeqNum;
+	Uint16 partitionFlags;
+	Uint16 partitionNumber;
+	EntityID partitionContents;
+	Uint8 partitionContentsUse[128];
+	Uint32 accessType;
+	Uint32 partitionStartingLocation;
+	Uint32 partitionLength;
+	EntityID impIdent;
+	Uint8 impUse[128];
+	Uint8 reserved[156];
+};
+
+/* Partition Flags (ECMA 167 3/10.5.3) */
+#define PARTITION_FLAGS_ALLOC	1
+
+/* Partition Contents (ECMA 167 3/10.5.5) */
+#define PARTITION_CONTENTS_FDC01	"+FDC01"
+#define PARTITION_CONTENTS_CD001	"+CD001"
+#define PARTITION_CONTENTS_CDW02	"+CDW02"
+#define PARTITION_CONTENTS_NSR02	"+NSR02"
+#define PARTITION_CONTENTS_NSR03	"+NSR03"
+
+/* Partition Access Types (ECMA 167 3/10.5.7) */
+#define PARTITION_ACCESS_NONE	0
+#define PARTITION_ACCESS_R	1
+#define PARTITION_ACCESS_WO	2
+#define PARTITION_ACCESS_RW	3
+#define PARTITION_ACCESS_OW	4
+
+/* Logical Volume Descriptor (ECMA 167 3/10.6) */
+struct LogicalVolDesc {
+	tag descTag;
+	Uint32 volDescSeqNum;
+	charspec descCharSet;
+	dstring logicalVolIdent[128];
+	Uint32 logicalBlockSize;
+	EntityID domainIdent;
+	Uint8 logicalVolContentsUse[16]; /* used to find fileset */
+	Uint32 mapTableLength;
+	Uint32 numPartitionMaps;
+	EntityID impIdent;
+	Uint8 impUse[128];
+	extent_ad integritySeqExt;
+	Uint8 partitionMaps[0];
+};
+
+/* Generic Partition Map (ECMA 167 3/10.7.1) */
+struct GenericPartitionMap {
+	Uint8 partitionMapType;
+	Uint8 partitionMapLength;
+	Uint8 partitionMapping[0];
+};
+
+/* Partition Map Type (ECMA 167 3/10.7.1.1) */
+#define PARTITION_MAP_TYPE_NONE		0
+#define PARTITION_MAP_TYPE_1		1
+#define PARTITION_MAP_TYPE_2		2
+
+/* Type 1 Partition Map (ECMA 167 3/10.7.2) */
+struct GenericPartitionMap1 {
+	Uint8 partitionMapType;
+	Uint8 partitionMapLength;
+	Uint16 volSeqNum;
+	Uint16 partitionNum;
+};
+
+/* Type 2 Partition Map (ECMA 167 3/10.7.3) */
+struct GenericPartitionMap2 {
+	Uint8 partitionMapType; /* 2 */
+	Uint8 partitionMapLength; 
+	Uint8 partitionIdent[62];
+};
+
+/* Unallocated Space Descriptor (ECMA 167 3/10.8) */
+struct UnallocatedSpaceDesc {
+	tag descTag;
+	Uint32 volDescSeqNum;
+	Uint32 numAllocDescs;
+	extent_ad allocDescs[0];
+};
+
+/* Terminating Descriptor (ECMA 3/10.9) */
+struct TerminatingDesc {
+	tag descTag;
+	Uint8 reserved[496];
+};
+
+struct GenericDesc
+{
+        tag descTag;
+        Uint32 volDescSeqNum;
+};
+
+/* Logical Volume Integrity Descriptor (ECMA 167 3/10.10) */
+struct LogicalVolIntegrityDesc {
+	tag descTag;
+	timestamp recordingDateAndTime;
+	Uint32 integrityType;
+	extent_ad nextIntegrityExt;
+	Uint8 logicalVolContentsUse[32];
+	Uint32 numOfPartitions;
+	Uint32 lengthOfImpUse;
+	Uint32 freeSpaceTable[0];
+	Uint32 sizeTable[0];
+	Uint8 impUse[0];
+};
+
+/* Integrity Types (ECMA 167 3/10.10.3) */
+#define INTEGRITY_TYPE_OPEN	0
+#define INTEGRITY_TYPE_CLOSE	1
+
+/* Recorded Address (ECMA 167 4/7.1) */
+typedef struct {
+	Uint32 logicalBlockNum;
+	Uint16 partitionReferenceNum;
+} lb_addr;
+
+/* Extent interpretation (ECMA 167 4/14.14.1.1) */
+#define EXTENT_RECORDED_ALLOCATED               0x00
+#define EXTENT_NOT_RECORDED_ALLOCATED           0x01
+#define EXTENT_NOT_RECORDED_NOT_ALLOCATED       0x02
+#define EXTENT_NEXT_EXTENT_ALLOCDECS            0x03
+
+/* Long Allocation Descriptor (ECMA 167 4/14.14.2) */
+typedef struct {
+	Uint32 extLength;
+	lb_addr extLocation;
+	Uint8 impUse[6];
+} long_ad;
+	/* upper 2 bits of extLength indicate type */
+
+/* File Set Descriptor (ECMA 167 4/14.1) */
+struct FileSetDesc {
+	tag descTag;
+	timestamp recordingDateAndTime;
+	Uint16 interchangeLvl;
+	Uint16 maxInterchangeLvl;
+	Uint32 charSetList;
+	Uint32 maxCharSetList;
+	Uint32 fileSetNum;
+	Uint32 fileSetDescNum;
+	charspec logicalVolIdentCharSet;
+	dstring logicalVolIdent[128];
+	charspec fileSetCharSet;
+	dstring fileSetIdent[32];
+	dstring copyrightFileIdent[32];
+	dstring abstractFileIdent[32];
+	long_ad rootDirectoryICB;
+	EntityID domainIdent;
+	long_ad nextExt;
+	long_ad streamDirectoryICB;
+	Uint8 reserved[32];
+};
+
+/* Short Allocation Descriptor (ECMA 167 4/14.14.1) */
+typedef struct {
+	Uint32 extLength;
+	Uint32 extPosition;
+} short_ad;
+
+/* Partition Header Descriptor (ECMA 167 4/14.3) */
+struct PartitionHeaderDesc {
+	short_ad unallocatedSpaceTable;
+	short_ad unallocatedSpaceBitmap;
+	short_ad partitionIntegrityTable;
+	short_ad freedSpaceTable;
+	short_ad freedSpaceBitmap;
+	Uint8 reserved[88];
+};
+
+/* File Identifier Descriptor (ECMA 167 4/14.4) */
+struct FileIdentDesc
+{
+	tag descTag;
+	Uint16 fileVersionNum; /* 1 */
+	Uint8 fileCharacteristics;
+	Uint8 lengthFileIdent;
+	long_ad icb;
+	Uint16 lengthOfImpUse;
+	Uint8 impUse[0];
+	Uint8 fileIdent[0];
+	Uint8 padding[0];
+};
+
+/* File Characteristics (ECMA 167 4/14.4.3) */
+#define FILE_HIDDEN	1
+#define FILE_DIRECTORY	2
+#define FILE_DELETED	4
+#define FILE_PARENT	8
+#define FILE_METADATA	0x10 /* UDF 2.0 */
+
+/* Allocation Ext Descriptor (ECMA 167 4/14.5) */
+struct AllocExtDesc
+{
+	tag descTag;
+	Uint32 previousAllocExtLocation;
+	Uint32 lengthAllocDescs;
+};
+
+/* ICB Tag (ECMA 167 4/14.6) */
+typedef struct {
+	Uint32 priorRecordedNumDirectEntries;
+	Uint16 strategyType;
+	Uint16 strategyParameter;
+	Uint16 numEntries;
+	Uint8 reserved;
+	Uint8 fileType;
+	lb_addr parentICBLocation;
+	Uint16 flags;
+} icbtag;
+
+/* ICB File Type (ECMA 167 4/14.6.6) */
+#define FILE_TYPE_NONE		0x00U
+#define FILE_TYPE_UNALLOC	0x01U
+#define FILE_TYPE_INTEGRITY	0x02U
+#define FILE_TYPE_INDIRECT	0x03U
+#define FILE_TYPE_DIRECTORY	0x04U
+#define FILE_TYPE_REGULAR	0x05U
+#define FILE_TYPE_BLOCK		0x06U
+#define FILE_TYPE_CHAR		0x07U
+#define FILE_TYPE_EXTENDED	0x08U
+#define FILE_TYPE_FIFO		0x09U
+#define FILE_TYPE_SOCKET	0x0aU
+#define FILE_TYPE_TERMINAL	0x0bU
+#define FILE_TYPE_SYMLINK	0x0cU
+#define FILE_TYPE_STREAMDIR	0x0dU /* ECMA 167 4/13 */
+
+/* ICB Flags (ECMA 167 4/14.6.8) */
+#define ICB_FLAG_ALLOC_MASK	0x0007U
+#define ICB_FLAG_SORTED		0x0008U
+#define ICB_FLAG_NONRELOCATABLE	0x0010U
+#define ICB_FLAG_ARCHIVE	0x0020U
+#define ICB_FLAG_SETUID		0x0040U
+#define ICB_FLAG_SETGID		0x0080U
+#define ICB_FLAG_STICKY		0x0100U
+#define ICB_FLAG_CONTIGUOUS	0x0200U
+#define ICB_FLAG_SYSTEM		0x0400U
+#define ICB_FLAG_TRANSFORMED	0x0800U
+#define ICB_FLAG_MULTIVERSIONS	0x1000U
+
+/* ICB Flags Allocation type(ECMA 167 4/14.6.8) */
+#define ICB_FLAG_AD_SHORT	0
+#define ICB_FLAG_AD_LONG	1
+#define ICB_FLAG_AD_EXTENDED	2
+#define ICB_FLAG_AD_IN_ICB	3
+
+/* Indirect Entry (ECMA 167 4/14.7) */
+struct IndirectEntry {
+	tag descTag;
+	icbtag icbTag;
+	long_ad indirectICB;
+};
+
+/* Terminal Entry (ECMA 167 4/14.8) */
+struct TerminalEntry {
+	tag descTag;
+	icbtag icbTag;
+};
+
+/* File Entry (ECMA 167 4/14.9) */
+struct FileEntry {
+	tag			descTag;
+	icbtag		icbTag;
+	Uint32		uid;
+	Uint32		gid;
+	Uint32		permissions;
+	Uint16		fileLinkCount;
+	Uint8		recordFormat;
+	Uint8		recordDisplayAttr;
+	Uint32		recordLength;
+	Uint64		informationLength;
+	Uint64		logicalBlocksRecorded;
+	timestamp	accessTime;
+	timestamp	modificationTime;
+	timestamp	attrTime;
+	Uint32		checkpoint;
+	long_ad		extendedAttrICB;
+	EntityID	impIdent;
+	Uint64		uniqueID; /* 0= root, 16- (2^32-1) */
+	Uint32		lengthExtendedAttr;
+	Uint32		lengthAllocDescs;
+	Uint8		extendedAttr[0];
+	Uint8		allocDescs[0];
+};
+
+/* File Permissions (ECMA 167 4/14.9.5) */
+#define PERM_O_EXEC	0x00000001U
+#define PERM_O_WRITE	0x00000002U
+#define PERM_O_READ	0x00000004U
+#define PERM_O_CHATTR	0x00000008U
+#define PERM_O_DELETE	0x00000010U
+#define PERM_G_EXEC	0x00000020U
+#define PERM_G_WRITE	0x00000040U
+#define PERM_G_READ	0x00000080U
+#define PERM_G_CHATTR	0x00000100U
+#define PERM_G_DELETE	0x00000200U
+#define PERM_U_EXEC	0x00000400U
+#define PERM_U_WRITE	0x00000800U
+#define PERM_U_READ	0x00001000U
+#define PERM_U_CHATTR	0x00002000U
+#define PERM_U_DELETE	0x00004000U
+
+/* File Record Format (ECMA 167 4/14.9.7) */
+#define RECORD_FMT_NONE			0
+#define RECORD_FMT_FIXED_PAD		1
+#define RECORD_FMT_FIXED		2
+#define RECORD_FMT_VARIABLE8		3
+#define RECORD_FMT_VARIABLE16		4
+#define RECORD_FMT_VARIABLE16_MSB	5
+#define RECORD_FMT_VARIABLE32		6
+#define RECORD_FMT_PRINT		7
+#define RECORD_FMT_LF			8
+#define RECORD_FMT_CR			9
+#define RECORD_FMT_CRLF			10
+#define RECORD_FMT_LFCR			10
+
+/* Extended Attribute Header Descriptor (ECMA 167 4/14.10.1) */
+struct ExtendedAttrHeaderDesc {
+	tag descTag;
+	Uint32 impAttrLocation;
+	Uint32 appAttrLocation;
+};
+
+/* Generic Attribute Format (ECMA 4/14.10.2) */
+struct GenericAttrFormat {
+	Uint32 attrType;
+	Uint8 attrSubtype;
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint8 attrData[0];
+};
+
+/* Character Set Attribute Format (ECMA 4/14.10.3) */
+struct CharSetAttrFormat {
+	Uint32 attrType;		/* 1 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint32 escapeSeqLength;
+	Uint8 charSetType;
+	Uint8 escapeSeq[0];
+};
+
+/* Alternate Permissions (ECMA 167 4/14.10.4) */
+struct AlternatePermissionsExtendedAttr {
+	Uint32 attrType;		/* 3 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint16 ownerIdent;
+	Uint16 groupIdent;
+	Uint16 permission;
+};
+
+/* File Times Extended Attribute (ECMA 167 4/14.10.5) */
+struct FileTimesExtendedAttr {
+	Uint32 attrType;		/* 5 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint32 dataLength;
+	Uint32 fileTimeExistence;
+	Uint8 fileTimes;
+};
+
+/* FileTimeExistence (ECMA 167 4/14.10.5.6) */
+#define FTE_CREATION	0
+#define FTE_DELETION	2
+#define FTE_EFFECTIVE	3
+#define FTE_BACKUP	5
+
+/* Information Times Extended Attribute (ECMA 167 4/14.10.6) */
+struct InfoTimesExtendedAttr {
+	Uint32 attrType;		/* 6 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint32 dataLength;
+	Uint32 infoTimeExistence;
+	Uint8 infoTimes[0];
+};
+
+/* Device Specification Extended Attribute (ECMA 167 4/14.10.7) */
+struct DeviceSpecificationExtendedAttr {
+	Uint32 attrType;		/* 12 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint32 impUseLength;
+	Uint32 majorDeviceIdent;
+	Uint32 minorDeviceIdent;
+	Uint8 impUse[0];
+};
+
+/* Implementation Use Extended Attr (ECMA 167 4/14.10.8) */
+struct ImpUseExtendedAttr {
+	Uint32 attrType;		/* 2048 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint32 impUseLength;
+	EntityID impIdent;
+	Uint8 impUse[0];
+};
+
+/* Application Use Extended Attribute (ECMA 167 4/14.10.9) */
+struct AppUseExtendedAttr {
+	Uint32 attrType;		/* 65536 */
+	Uint8 attrSubtype;		/* 1 */
+	Uint8 reserved[3];
+	Uint32 attrLength;
+	Uint32 appUseLength;
+	EntityID appIdent;
+	Uint8 appUse[0];
+};
+
+#define EXTATTR_CHAR_SET	1
+#define EXTATTR_ALT_PERMS	3
+#define EXTATTR_FILE_TIMES	5
+#define EXTATTR_INFO_TIMES	6
+#define EXTATTR_DEV_SPEC	12
+#define EXTATTR_IMP_USE		2048
+#define EXTATTR_APP_USE		65536
+
+
+/* Unallocated Space Entry (ECMA 167 4/14.11) */
+struct UnallocatedSpaceEntry {
+	tag descTag;
+	icbtag icbTag;
+	Uint32 lengthAllocDescs;
+	Uint8 allocDescs[0];
+};
+
+/* Space Bitmap Descriptor (ECMA 167 4/14.12) */
+struct SpaceBitmapDesc {
+	tag descTag;
+	Uint32 numOfBits;
+	Uint32 numOfBytes;
+	Uint8 bitmap[0];
+};
+
+/* Partition Integrity Entry (ECMA 167 4/14.13) */
+struct PartitionIntegrityEntry {
+	tag descTag;
+	icbtag icbTag;
+	timestamp recordingDateAndTime;
+	Uint8 integrityType;
+	Uint8 reserved[175];
+	EntityID impIdent;
+	Uint8 impUse[256];
+};
+
+/* Extended Allocation Descriptor (ECMA 167 4/14.14.3) */
+typedef struct { /* ECMA 167 4/14.14.3 */
+	Uint32 extLength;
+	Uint32 recordedLength;
+	Uint32 informationLength;
+	lb_addr extLocation;
+} ext_ad;
+
+/* Logical Volume Header Descriptor (ECMA 167 4/14.5) */
+struct LogicalVolHeaderDesc {
+	Uint64 uniqueID;
+	Uint8 reserved[24];
+};
+
+/* Path Component (ECMA 167 4/14.16.1) */
+struct PathComponent {
+	Uint8 componentType;
+	Uint8 lengthComponentIdent;
+	Uint16 componentFileVersionNum;
+	dstring componentIdent[0];
+};
+
+/* File Entry (ECMA 167 4/14.17) */
+struct ExtendedFileEntry {
+	tag			descTag;
+	icbtag		icbTag;
+	Uint32		uid;
+	Uint32		gid;
+	Uint32		permissions;
+	Uint16		fileLinkCount;
+	Uint8		recordFormat;
+	Uint8		recordDisplayAttr;
+	Uint32		recordLength;
+	Uint64		informationLength;
+	Uint64		objectSize;
+	Uint64		logicalBlocksRecorded;
+	timestamp	accessTime;
+	timestamp	modificationTime;
+	timestamp	createTime;
+	timestamp	attrTime;
+	Uint32		checkpoint;
+	Uint32		reserved;
+	long_ad		extendedAttrICB;
+	long_ad		streamDirectoryICB;
+	EntityID	impIdent;
+	Uint64		uniqueID;
+	Uint32		lengthExtendedAttr;
+	Uint32		lengthAllocDescs;
+	Uint8		extendedAttr[0];
+	Uint8		allocDescs[0];
+};
+#pragma pack()
+
+#endif /* !defined(_LINUX_UDF_167_H) */
diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_fs.h linux/include/linux/udf_fs.h
--- v2.3.16/linux/include/linux/udf_fs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/udf_fs.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,63 @@
+/*
+ * udf_fs.h
+ *
+ * Included by fs/filesystems.c
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ * HISTORY
+ *	July 21, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ *
+ * 10/2/98 dgb	rearranged all headers
+ * 11/26/98 bf  added byte order macros
+ * 12/5/98 dgb  removed other includes to reduce kernel namespace pollution.
+ *		This should only be included by the kernel now!
+ */
+#if !defined(_LINUX_UDF_FS_H)
+#define _LINUX_UDF_FS_H
+
+#define UDF_PREALLOCATE
+#define UDF_DEFAULT_PREALLOC_BLOCKS		8
+#define UDF_DEFAULT_PREALLOC_DIR_BLOCKS	0
+
+#define UDFFS_DATE		"99/09/02"
+#define UDFFS_VERSION	"0.8.9"
+#define UDFFS_DEBUG
+
+#ifdef UDFFS_DEBUG
+#define udf_debug(f, a...) \
+	{ \
+		printk (KERN_DEBUG "UDF-fs DEBUG (%s, %d): %s: ", \
+			__FILE__, __LINE__, __FUNCTION__); \
+		printk (## f, ## a); \
+	}
+#else
+#define udf_debug(f, a...) /**/
+#endif
+
+#define udf_info(f, a...) \
+		printk (KERN_INFO "UDF-fs INFO " ## f, ## a);
+
+struct udf_addr
+{
+	__u32 block;
+	__u16 partition;
+	unsigned error : 1;
+	unsigned reserved : 15;
+};
+	
+
+/* Prototype for fs/filesystem.c (the only thing really required in this file) */
+extern int init_udf_fs(void);
+
+#endif /* !defined(_LINUX_UDF_FS_H) */
diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_fs_i.h linux/include/linux/udf_fs_i.h
--- v2.3.16/linux/include/linux/udf_fs_i.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/udf_fs_i.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,60 @@
+/*
+ * udf_fs_i.h
+ *
+ * This file is intended for the Linux kernel/module. 
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ */
+
+#if !defined(_LINUX_UDF_FS_I_H)
+#define _LINUX_UDF_FS_I_H
+
+#ifdef __KERNEL__
+
+#ifndef _LINUX_UDF_167_H
+typedef struct
+{
+	__u32 logicalBlockNum;
+	__u16 partitionReferenceNum;
+} lb_addr;
+#endif
+
+struct udf_inode_info
+{
+	long i_uatime;
+	long i_umtime;
+	long i_uctime;
+	/* Physical address of inode */
+	lb_addr i_ext0Location;	/* partition relative */
+	lb_addr i_location;
+	__u32 i_ext0Length;  	/* in blocks */
+	__u32 i_ext0Offset;	/* for short directories */
+	__u64 i_unique;
+	__u32 i_lenEAttr;
+	__u32 i_lenAlloc;
+	__u32 i_next_alloc_block;
+	__u32 i_next_alloc_goal;
+	unsigned i_alloc_type : 3;
+	unsigned i_extended_fe : 1;
+	unsigned i_strat_4096 : 1;
+	unsigned reserved : 27;
+};
+
+#endif
+
+/* exported IOCTLs, we have 'l', 0x40-0x7f */
+
+#define UDF_GETEASIZE   _IOR('l', 0x40, int)
+#define UDF_GETEABLOCK  _IOR('l', 0x41, void *)
+#define UDF_GETVOLIDENT _IOR('l', 0x42, void *)
+
+#endif /* !defined(_LINUX_UDF_FS_I_H) */
diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_fs_sb.h linux/include/linux/udf_fs_sb.h
--- v2.3.16/linux/include/linux/udf_fs_sb.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/udf_fs_sb.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,108 @@
+/*
+ * udf_fs_sb.h
+ * 
+ * This include file is for the Linux kernel/module.
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ */
+
+#if !defined(_LINUX_UDF_FS_SB_H)
+#define _LINUX_UDF_FS_SB_H
+
+#pragma pack(1)
+
+#define UDF_MAX_BLOCK_LOADED	8
+
+#define UDF_TYPE1_MAP15			0x1511U
+#define UDF_VIRTUAL_MAP15		0x1512U
+#define UDF_VIRTUAL_MAP20		0x2012U
+#define UDF_SPARABLE_MAP15		0x1522U
+
+struct udf_sparing_data
+{
+	__u32	  s_spar_loc;
+	__u16	  s_spar_plen;
+};
+
+struct udf_virtual_data
+{
+	__u32	  s_num_entries;
+	__u16	  s_start_offset;
+};
+
+struct udf_part_map
+{
+	__u32	s_uspace_bitmap;
+	__u32	s_partition_root;
+	__u32	s_partition_len;
+	__u16	s_partition_type;
+	__u16	s_partition_num;
+	union
+	{
+		struct udf_sparing_data s_sparing;
+		struct udf_virtual_data s_virtual;
+	} s_type_specific;
+	__u16	s_volumeseqnum;
+};
+
+#pragma pack()
+
+struct udf_sb_info
+{
+	struct udf_part_map *s_partmaps;
+	__u8  s_volident[32];
+
+	/* Overall info */
+	__u16 s_partitions;
+	__u16 s_partition;
+
+	/* Sector headers */
+	__u32 s_session;
+	__u32 s_anchor[4];
+	__u32 s_lastblock;
+
+	struct buffer_head *s_lvidbh;
+
+	lb_addr s_location;
+
+	__u16 s_loaded_block_bitmaps;
+	__u32 s_block_bitmap_number[UDF_MAX_BLOCK_LOADED];
+	struct buffer_head *s_block_bitmap[UDF_MAX_BLOCK_LOADED];
+
+	/* Default permissions */
+	mode_t s_umask;
+	gid_t s_gid;
+	uid_t s_uid;
+
+	/* Root Info */
+	time_t s_recordtime;
+
+	/* Fileset Info */
+	__u16 s_serialnum;
+
+	/* Character Mapping Info */
+	struct nls_table *s_nls_iocharset;
+	__u8 s_utf8;
+
+	/* Miscellaneous flags */
+	__u32 s_flags;
+
+	/* VAT inode */
+	struct inode    *s_vat;
+
+#if LINUX_VERSION_CODE < 0x020206
+	int s_rename_lock;
+	struct wait_queue * s_rename_wait;
+#endif
+};
+
+#endif /* !defined(_LINUX_UDF_FS_SB_H) */
diff -u --recursive --new-file v2.3.16/linux/include/linux/udf_udf.h linux/include/linux/udf_udf.h
--- v2.3.16/linux/include/linux/udf_udf.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/udf_udf.h	Sat Sep  4 12:42:30 1999
@@ -0,0 +1,228 @@
+#if !defined(_LINUX_UDF_UDF_H)
+#define _LINUX_UDF_UDF_H
+/*
+ * udf_udf.h
+ *
+ * PURPOSE
+ *	OSTA-UDF(tm) format specification [based on ECMA 167 standard].
+ *	http://www.osta.org/
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hootie.lvld.hp.com
+ *
+ * COPYRIGHT
+ *	This file is distributed under the terms of the GNU General Public
+ *	License (GPL). Copies of the GPL can be obtained from:
+ *		ftp://prep.ai.mit.edu/pub/gnu/GPL
+ *	Each contributing author retains all rights to their own work.
+ *
+ * HISTORY
+ *	July 1, 1997 - Andrew E. Mileski
+ *	Written, tested, and released.
+ *
+ * 10/2/98 dgb	changed UDF_ID_DEVELOPER
+ * 11/26/98 bf  changed UDF_ID_DEVELOPER, 
+ * 12/5/98 dgb  updated include file hierarchy, more UDF definitions
+ */
+
+/* based on ECMA 167 structure definitions */
+#include <linux/udf_167.h>
+
+#pragma pack(1)
+
+/* -------- Basic types and constants ----------- */
+/* UDF character set (UDF 1.50 2.1.2) */
+#define UDF_CHAR_SET_TYPE	0
+#define UDF_CHAR_SET_INFO	"OSTA Compressed Unicode"
+
+#define UDF_ID_DEVELOPER	"*Linux UDFFS"
+ 
+/* UDF 1.02 2.2.6.4 */
+struct LogicalVolIntegrityDescImpUse
+{
+	EntityID	impIdent;
+	Uint32		numFiles;
+	Uint32		numDirs;
+	Uint16		minUDFReadRev;
+	Uint16		minUDFWriteRev;
+	Uint16		maxUDFWriteRev;
+};
+
+/* UDF 1.02 2.2.7.2 */
+/* LVInformation may be present in ImpUseVolDesc.impUse */
+struct ImpUseVolDescImpUse
+{
+	charspec	LVICharset;
+	dstring		logicalVolIdent[128];
+	dstring		LVInfo1[36];
+	dstring		LVInfo2[36];
+	dstring		LVInfo3[36];
+	EntityID	impIdent;
+	Uint8		impUse[128];
+};
+
+struct UdfPartitionMap2
+{
+        Uint8           partitionMapType;
+        Uint8           partitionMapLength;
+        Uint8           reserved1[2];
+        EntityID        partIdent;
+        Uint16          volSeqNum;
+        Uint16          partitionNum;
+        Uint8           reserved2[24];
+};
+
+/* UDF 1.5 2.2.8 */
+struct VirtualPartitionMap
+{
+	Uint8		partitionMapType;	/* 2 */
+	Uint8		partitionMapLength;	/* 64 */
+	Uint8		reserved1[2];		/* #00 */
+	EntityID	partIdent;
+	Uint16		volSeqNum;
+	Uint16		partitionNum;
+	Uint8		reserved2[24];		/* #00 */
+};
+
+/* UDF 1.5 2.2.9 */
+struct SparablePartitionMap
+{
+	Uint8		partitionMapType;	/* 2 */
+	Uint8		partitionMapLength;	/* 64 */
+	Uint8		reserved1[2];		/* #00 */
+	EntityID	partIdent;		/* Flags = 0 */
+						/* Id = UDF_ID_SPARABLE */
+						/* IdSuf = 2.1.5.3 */
+	Uint16		volSeqNum;
+	Uint16		partitionNum;
+	Uint16		packetLength;		/* 32 */
+	Uint8		numSparingTables;
+	Uint8		reserved2[1];		/* #00 */
+	Uint32		sizeSparingTable;
+	Uint32		locSparingTable[0];
+	Uint8		pad[0];
+};
+ 
+/* DVD Copyright Management Info, see UDF 1.02 3.3.4.5.1.2 */
+/* when ImpUseExtendedAttr.impIdent= "*UDF DVD CGMS Info" */
+struct DVDCopyrightImpUse {
+	Uint16 headerChecksum;
+	Uint8  CGMSInfo;
+	Uint8  dataType;
+	Uint8  protectionSystemInfo[4];
+};
+
+/* the impUse of long_ad used in AllocDescs  - UDF 1.02 2.3.10.1 */
+struct ADImpUse
+{
+	Uint16 flags;
+	Uint8  impUse[4];
+};
+
+/* UDF 1.02 2.3.10.1 */
+#define UDF_EXTENT_LENGTH_MASK		0x3FFFFFFF
+#define UDF_EXTENT_FLAG_MASK		0xc0000000
+#define UDF_EXTENT_FLAG_ERASED		0x40000000
+
+/* 
+ * Important!  VirtualAllocationTables are 
+ * very different between 1.5 and 2.0!
+ */
+
+/* ----------- 1.5 ------------- */
+/* UDF 1.5 2.2.10 */
+#define FILE_TYPE_VAT15		0x0U
+
+/* UDF 1.5 2.2.10 - VAT layout: */
+struct VirutalAllocationTable15 {
+	Uint32 VirtualSector[0];
+	EntityID	ident;
+	Uint32	previousVATICB;
+   };  
+/* where number of VirtualSector's is (VATSize-36)/4 */
+
+/* ----------- 2.0 ------------- */
+/* UDF 2.0 2.2.10 */
+#define FILE_TYPE_VAT20		0xf8U
+
+/* UDF 2.0 2.2.10 (different from 1.5!) */
+struct VirtualAllocationTable20 {
+	Uint16 lengthHeader;
+	Uint16 lengthImpUse;
+	dstring logicalVolIdent[128];
+	Uint32	previousVatICBLoc;
+	Uint32  numFIDSFiles;
+	Uint32  numFIDSDirectories; /* non-parent */
+	Uint16  minReadRevision;
+	Uint16	minWriteRevision;
+	Uint16  maxWriteRevision;
+	Uint16  reserved;
+	Uint8	impUse[0];
+	Uint32  vatEntry[0];
+};
+
+/* Sparing maps, see UDF 1.5 2.2.11 */
+typedef struct {
+	Uint32  origLocation;
+	Uint32  mappedLocation;
+} SparingEntry;
+
+/* sparing maps, see UDF 2.0 2.2.11 */
+struct SparingTable {
+	tag 	descTag;
+	EntityID sparingIdent; /* *UDF Sparing Table */
+	Uint16   reallocationTableLen;
+	Uint16   reserved;	/* #00 */
+	Uint32   sequenceNum;
+	SparingEntry mapEntry[0];
+};
+
+/* Entity Identifiers (UDF 1.50 6.1) */
+#define	UDF_ID_COMPLIANT	"*OSTA UDF Compliant"
+#define UDF_ID_LV_INFO		"*UDF LV Info"
+#define UDF_ID_FREE_EA		"*UDF FreeEASpace"
+#define UDF_ID_FREE_APP_EA	"*UDF FreeAppEASpace"
+#define UDF_ID_DVD_CGMS		"*UDF DVD CGMS Info"
+#define UDF_ID_OS2_EA		"*UDF OS/2 EA"
+#define UDF_ID_OS2_EA_LENGTH	"*UDF OS/2 EALength"
+#define UDF_ID_MAC_VOLUME	"*UDF Mac VolumeInfo"
+#define UDF_ID_MAC_FINDER	"*UDF Mac FinderInfo"
+#define UDF_ID_MAC_UNIQUE	"*UDF Mac UniqueIDTable"
+#define UDF_ID_MAC_RESOURCE	"*UDF Mac ResourceFork"
+#define UDF_ID_VIRTUAL		"*UDF Virtual Partition"
+#define UDF_ID_SPARABLE		"*UDF Sparable Partition"
+#define UDF_ID_ALLOC		"*UDF Virtual Alloc Tbl"
+#define UDF_ID_SPARING		"*UDF Sparing Table"
+
+/* Operating System Identifiers (UDF 1.50 6.3) */
+#define UDF_OS_CLASS_UNDEF	0x00U
+#define UDF_OS_CLASS_DOS	0x01U
+#define UDF_OS_CLASS_OS2	0x02U
+#define UDF_OS_CLASS_MAC	0x03U
+#define UDF_OS_CLASS_UNIX	0x04U
+#define UDF_OS_CLASS_WIN95	0x05U
+#define UDF_OS_CLASS_WINNT	0x06U
+#define UDF_OS_ID_UNDEF		0x00U
+#define UDF_OS_ID_DOS		0x00U
+#define UDF_OS_ID_OS2		0x00U
+#define UDF_OS_ID_MAC		0x00U
+#define UDF_OS_ID_UNIX		0x00U
+#define UDF_OS_ID_WIN95		0x00U
+#define UDF_OS_ID_WINNT		0x00U
+#define UDF_OS_ID_AIX		0x01U
+#define UDF_OS_ID_SOLARIS	0x02U
+#define UDF_OS_ID_HPUX		0x03U
+#define UDF_OS_ID_IRIX		0x04U
+#define UDF_OS_ID_LINUX		0x05U
+#define UDF_OS_ID_MKLINUX	0x06U
+#define UDF_OS_ID_FREEBSD	0x07U
+
+#define UDF_NAME_PAD	4
+#define UDF_NAME_LEN	255
+#define UDF_PATH_LEN	1023
+
+#pragma pack()
+
+#endif /* !defined(_LINUX_UDF_FMT_H) */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/bulkmem.h linux/include/pcmcia/bulkmem.h
--- v2.3.16/linux/include/pcmcia/bulkmem.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/bulkmem.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,195 @@
+/*
+ * Definitions for bulk memory services
+ *
+ * bulkmem.h 1.10 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ * bulkmem.h 1.3 1995/05/27 04:49:49
+ */
+
+#ifndef _LINUX_BULKMEM_H
+#define _LINUX_BULKMEM_H
+
+/* For GetFirstRegion and GetNextRegion */
+typedef struct region_info_t {
+    u_int		Attributes;
+    u_int		CardOffset;
+    u_int		RegionSize;
+    u_int		AccessSpeed;
+    u_int		BlockSize;
+    u_int		PartMultiple;
+    u_char		JedecMfr, JedecInfo;
+    memory_handle_t	next;
+} region_info_t;
+
+#define REGION_TYPE		0x0001
+#define REGION_TYPE_CM		0x0000
+#define REGION_TYPE_AM		0x0001
+#define REGION_PREFETCH		0x0008
+#define REGION_CACHEABLE	0x0010
+#define REGION_BAR_MASK		0xe000
+#define REGION_BAR_SHIFT	13
+
+/* For OpenMemory */
+typedef struct open_mem_t {
+    u_int		Attributes;
+    u_int		Offset;
+} open_mem_t;
+
+/* Attributes for OpenMemory */
+#define MEMORY_TYPE		0x0001
+#define MEMORY_TYPE_CM		0x0000
+#define MEMORY_TYPE_AM		0x0001
+#define MEMORY_EXCLUSIVE	0x0002
+#define MEMORY_PREFETCH		0x0008
+#define MEMORY_CACHEABLE	0x0010
+#define MEMORY_BAR_MASK		0xe000
+#define MEMORY_BAR_SHIFT	13
+
+typedef struct eraseq_entry_t {
+    memory_handle_t	Handle;
+    u_char		State;
+    u_int		Size;
+    u_int		Offset;
+    void		*Optional;
+} eraseq_entry_t;
+
+typedef struct eraseq_hdr_t {
+    int			QueueEntryCnt;
+    eraseq_entry_t	*QueueEntryArray;
+} eraseq_hdr_t;
+
+#define ERASE_QUEUED		0x00
+#define ERASE_IN_PROGRESS(n)	(((n) > 0) && ((n) < 0x80))
+#define ERASE_IDLE		0xff
+#define ERASE_PASSED		0xe0
+#define ERASE_FAILED		0xe1
+
+#define ERASE_MISSING		0x80
+#define ERASE_MEDIA_WRPROT	0x84
+#define ERASE_NOT_ERASABLE	0x85
+#define ERASE_BAD_OFFSET	0xc1
+#define ERASE_BAD_TECH		0xc2
+#define ERASE_BAD_SOCKET	0xc3
+#define ERASE_BAD_VCC		0xc4
+#define ERASE_BAD_VPP		0xc5
+#define ERASE_BAD_SIZE		0xc6
+
+/* For CopyMemory */
+typedef struct copy_op_t {
+    u_int		Attributes;
+    u_int		SourceOffset;
+    u_int		DestOffset;
+    u_int		Count;
+} copy_op_t;
+
+/* For ReadMemory and WriteMemory */
+typedef struct mem_op_t {
+    u_int	Attributes;
+    u_int	Offset;
+    u_int	Count;
+} mem_op_t;
+
+#define MEM_OP_BUFFER		0x01
+#define MEM_OP_BUFFER_USER	0x00
+#define MEM_OP_BUFFER_KERNEL	0x01
+#define MEM_OP_DISABLE_ERASE	0x02
+#define MEM_OP_VERIFY		0x04
+
+/* For RegisterMTD */
+typedef struct mtd_reg_t {
+    u_int	Attributes;
+    u_int	Offset;
+    u_long	MediaID;
+} mtd_reg_t;
+
+/*
+ *  Definitions for MTD requests
+ */
+
+typedef struct mtd_request_t {
+    u_int	SrcCardOffset;
+    u_int	DestCardOffset;
+    u_int	TransferLength;
+    u_int	Function;
+    u_long	MediaID;
+    u_int	Status;
+    u_int	Timeout;
+} mtd_request_t;
+
+/* Fields in MTD Function */
+#define MTD_REQ_ACTION		0x003
+#define MTD_REQ_ERASE		0x000
+#define MTD_REQ_READ		0x001
+#define MTD_REQ_WRITE		0x002
+#define MTD_REQ_COPY		0x003
+#define MTD_REQ_NOERASE		0x004
+#define MTD_REQ_VERIFY		0x008
+#define MTD_REQ_READY		0x010
+#define MTD_REQ_TIMEOUT		0x020
+#define MTD_REQ_LAST		0x040
+#define MTD_REQ_FIRST		0x080
+#define MTD_REQ_KERNEL		0x100
+
+/* Status codes */
+#define MTD_WAITREQ	0x00
+#define MTD_WAITTIMER	0x01
+#define MTD_WAITRDY	0x02
+#define MTD_WAITPOWER	0x03
+
+/*
+ *  Definitions for MTD helper functions
+ */
+
+/* For MTDModifyWindow */
+typedef struct mtd_mod_win_t {
+    u_int	Attributes;
+    u_int	AccessSpeed;
+    u_int	CardOffset;
+} mtd_mod_win_t;
+
+/* For MTDSetVpp */
+typedef struct mtd_vpp_req_t {
+    u_char	Vpp1, Vpp2;
+} mtd_vpp_req_t;
+
+/* For MTDRDYMask */
+typedef struct mtd_rdy_req_t {
+    u_int	Mask;
+} mtd_rdy_req_t;
+
+enum mtd_helper {
+    MTDRequestWindow, MTDModifyWindow, MTDReleaseWindow,
+    MTDSetVpp, MTDRDYMask
+};
+
+#ifdef IN_CARD_SERVICES
+extern int MTDHelperEntry(int func, void *a1, void *a2);
+#else
+extern int MTDHelperEntry(int func, ...);
+#endif
+
+#endif /* _LINUX_BULKMEM_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/bus_ops.h linux/include/pcmcia/bus_ops.h
--- v2.3.16/linux/include/pcmcia/bus_ops.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/bus_ops.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,150 @@
+/*
+ * bus_ops.h 1.6 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_BUS_OPS_H
+#define _LINUX_BUS_OPS_H
+
+typedef struct bus_operations {
+    void	*priv;
+    u32		(*b_in)(void *bus, u32 port, s32 sz);
+    void	(*b_ins)(void *bus, u32 port, void *buf,
+			 u32 count, s32 sz);
+    void	(*b_out)(void *bus, u32 val, u32 port, s32 sz);
+    void	(*b_outs)(void *bus, u32 port, void *buf,
+			  u32 count, s32 sz);
+    void	*(*b_ioremap)(void *bus, u_long ofs, u_long sz);
+    void	(*b_iounmap)(void *bus, void *addr);
+    u32		(*b_read)(void *bus, void *addr, s32 sz);
+    void	(*b_write)(void *bus, u32 val, void *addr, s32 sz);
+    void	(*b_copy_from)(void *bus, void *d, void *s, u32 count);
+    void	(*b_copy_to)(void *bus, void *d, void *s, u32 count);
+    int		(*b_request_irq)(void *bus, u_int irq,
+				 void (*handler)(int, void *,
+						 struct pt_regs *),
+				 u_long flags, const char *device,
+				 void *dev_id);
+    void	(*b_free_irq)(void *bus, u_int irq, void *dev_id);
+} bus_operations;
+
+#ifdef CONFIG_VIRTUAL_BUS
+
+#define bus_inb(b,p)		(b)->b_in((b),(p),0)
+#define bus_inw(b,p)		(b)->b_in((b),(p),1)
+#define bus_inl(b,p)		(b)->b_in((b),(p),2)
+#define bus_inw_ns(b,p)		(b)->b_in((b),(p),-1)
+#define bus_inl_ns(b,p)		(b)->b_in((b),(p),-2)
+
+#define bus_insb(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),0)
+#define bus_insw(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),1)
+#define bus_insl(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),2)
+#define bus_insw_ns(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),-1)
+#define bus_insl_ns(b,p,a,c)	(b)->b_ins((b),(p),(a),(c),-2)
+
+#define bus_outb(b,v,p)		(b)->b_out((b),(v),(p),0)
+#define bus_outw(b,v,p)		(b)->b_out((b),(v),(p),1)
+#define bus_outl(b,v,p)		(b)->b_out((b),(v),(p),2)
+#define bus_outw_ns(b,v,p)	(b)->b_out((b),(v),(p),-1)
+#define bus_outl_ns(b,v,p)	(b)->b_out((b),(v),(p),-2)
+
+#define bus_outsb(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),0)
+#define bus_outsw(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),1)
+#define bus_outsl(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),2)
+#define bus_outsw_ns(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),-1)
+#define bus_outsl_ns(b,p,a,c)	(b)->b_outs((b),(p),(a),(c),-2)
+
+#define bus_readb(b,a)		(b)->b_read((b),(a),0)
+#define bus_readw(b,a)		(b)->b_read((b),(a),1)
+#define bus_readl(b,a)		(b)->b_read((b),(a),2)
+#define bus_readw_ns(b,a)	(b)->b_read((b),(a),-1)
+#define bus_readl_ns(b,a)	(b)->b_read((b),(a),-2)
+
+#define bus_writeb(b,v,a)	(b)->b_write((b),(v),(a),0)
+#define bus_writew(b,v,a)	(b)->b_write((b),(v),(a),1)
+#define bus_writel(b,v,a)	(b)->b_write((b),(v),(a),2)
+#define bus_writew_ns(b,v,a)	(b)->b_write((b),(v),(a),-1)
+#define bus_writel_ns(b,v,a)	(b)->b_write((b),(v),(a),-2)
+
+#define bus_ioremap(b,s,n)	(b)->b_ioremap((b),(s),(n))
+#define bus_iounmap(b,a)	(b)->b_iounmap((b),(a))
+#define bus_memcpy_fromio(b,d,s,n) (b)->b_copy_from((b),(d),(s),(n))
+#define bus_memcpy_toio(b,d,s,n) (b)->b_copy_to((b),(d),(s),(n))
+
+#define bus_request_irq(b,i,h,f,n,d) \
+				(b)->b_request_irq((b),(i),(h),(f),(n),(d))
+#define bus_free_irq(b,i,d)	(b)->b_free_irq((b),(i),(d))
+
+#else
+
+#define bus_inb(b,p)		inb(p)
+#define bus_inw(b,p)		inw(p)
+#define bus_inl(b,p)		inl(p)
+#define bus_inw_ns(b,p)		inw_ns(p)
+#define bus_inl_ns(b,p)		inl_ns(p)
+
+#define bus_insb(b,p,a,c)	insb(p,a,c)
+#define bus_insw(b,p,a,c)	insw(p,a,c)
+#define bus_insl(b,p,a,c)	insl(p,a,c)
+#define bus_insw_ns(b,p,a,c)	insw_ns(p,a,c)
+#define bus_insl_ns(b,p,a,c)	insl_ns(p,a,c)
+
+#define bus_outb(b,v,p)		outb(b,v,p)
+#define bus_outw(b,v,p)		outw(b,v,p)
+#define bus_outl(b,v,p)		outl(b,v,p)
+#define bus_outw_ns(b,v,p)	outw_ns(b,v,p)
+#define bus_outl_ns(b,v,p)	outl_ns(b,v,p)
+
+#define bus_outsb(b,p,a,c)	outsb(p,a,c)
+#define bus_outsw(b,p,a,c)	outsw(p,a,c)
+#define bus_outsl(b,p,a,c)	outsl(p,a,c)
+#define bus_outsw_ns(b,p,a,c)	outsw_ns(p,a,c)
+#define bus_outsl_ns(b,p,a,c)	outsl_ns(p,a,c)
+
+#define bus_readb(b,a)		readb(a)
+#define bus_readw(b,a)		readw(a)
+#define bus_readl(b,a)		readl(a)
+#define bus_readw_ns(b,a)	readw_ns(a)
+#define bus_readl_ns(b,a)	readl_ns(a)
+
+#define bus_writeb(b,v,a)	writeb(v,a)
+#define bus_writew(b,v,a)	writew(v,a)
+#define bus_writel(b,v,a)	writel(v,a)
+#define bus_writew_ns(b,v,a)	writew_ns(v,a)
+#define bus_writel_ns(b,v,a)	writel_ns(v,a)
+
+#define bus_ioremap(b,s,n)	ioremap(s,n)
+#define bus_iounmap(b,a)	iounmap(a)
+#define bus_memcpy_fromio(b,d,s,n) memcpy_fromio(d,s,n)
+#define bus_memcpy_toio(b,d,s,n) memcpy_toio(d,s,n)
+
+#define bus_request_irq(b,i,h,f,n,d) request_irq((i),(h),(f),(n),(d))
+#define bus_free_irq(b,i,d)	free_irq((i),(d))
+
+#endif /* CONFIG_VIRTUAL_BUS */
+
+#endif /* _LINUX_BUS_OPS_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ciscode.h linux/include/pcmcia/ciscode.h
--- v2.3.16/linux/include/pcmcia/ciscode.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/ciscode.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,115 @@
+/*
+ * ciscode.h 1.38 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISCODE_H
+#define _LINUX_CISCODE_H
+
+/* Manufacturer and Product ID codes */
+
+#define MANFID_3COM			0x0101
+#define PRODID_3COM_3CXEM556		0x0035
+#define PRODID_3COM_3CCFEM556		0x0556
+#define PRODID_3COM_3C562		0x0562
+
+#define MANFID_ACCTON			0x01bf
+#define PRODID_ACCTON_EN2226		0x010a
+
+#define MANFID_ADAPTEC			0x012f
+#define PRODID_ADAPTEC_SCSI		0x0001
+
+#define MANFID_ATT			0xffff
+#define PRODID_ATT_KIT			0x0100
+
+#define MANFID_CONTEC			0xc001
+
+#define MANFID_FUJITSU			0x0004
+#define PRODID_FUJITSU_MBH10302		0x0004
+#define PRODID_FUJITSU_MBH10304		0x1003
+#define PRODID_FUJITSU_LA501		0x2000
+
+#define MANFID_IBM			0x00a4
+#define PRODID_IBM_HOME_AND_AWAY	0x002e
+
+#define MANFID_INTEL			0x0089
+#define PRODID_INTEL_DUAL_RS232		0x0301
+#define PRODID_INTEL_2PLUS		0x8422
+
+#define MANFID_LINKSYS			0x0143
+#define PRODID_LINKSYS_PCMLM28		0xc0ab
+#define PRODID_LINKSYS_3400		0x3341
+
+#define MANFID_MEGAHERTZ		0x0102
+#define PRODID_MEGAHERTZ_VARIOUS	0x0000
+#define PRODID_MEGAHERTZ_EM3288		0x0006
+
+#define MANFID_MACNICA			0xc00b
+
+#define MANFID_MOTOROLA			0x0109
+#define PRODID_MOTOROLA_MARINER		0x0501
+
+#define MANFID_NATINST			0x010b
+#define PRODID_NATINST_QUAD_RS232	0xd180
+
+#define MANFID_NEW_MEDIA		0x0057
+
+#define MANFID_OLICOM			0x0121
+#define PRODID_OLICOM_OC2231		0x3122
+#define PRODID_OLICOM_OC2232		0x3222
+
+#define MANFID_OMEGA			0x0137
+#define PRODID_OMEGA_QSP_100		0x0025
+
+#define MANFID_OSITECH			0x0140
+#define PRODID_OSITECH_JACK_144		0x0001
+#define PRODID_OSITECH_JACK_288		0x0002
+#define PRODID_OSITECH_JACK_336		0x0007
+#define PRODID_OSITECH_SEVEN		0x0008
+
+#define MANFID_PSION			0x016c
+
+#define MANFID_QUATECH			0x0137
+#define PRODID_QUATECH_SPP100		0x0003
+#define PRODID_QUATECH_DUAL_RS232	0x0012
+#define PRODID_QUATECH_DUAL_RS232_D1	0x0007
+#define PRODID_QUATECH_QUAD_RS232	0x001b
+
+#define MANFID_SMC			0x0108
+#define PRODID_SMC_ETHER		0x0105
+
+#define MANFID_SOCKET			0x0104
+#define PRODID_SOCKET_DUAL_RS232	0x0006
+#define PRODID_SOCKET_LPE		0x000d
+
+#define MANFID_SUNDISK			0x0045
+
+#define MANFID_TDK			0x0105
+
+#define MANFID_XIRCOM			0x0105
+
+#endif /* _LINUX_CISCODE_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cisreg.h linux/include/pcmcia/cisreg.h
--- v2.3.16/linux/include/pcmcia/cisreg.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/cisreg.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,116 @@
+/*
+ * cisreg.h 1.13 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISREG_H
+#define _LINUX_CISREG_H
+
+/* Offsets from ConfigBase for CIS registers */
+#define CISREG_COR		0x00
+#define CISREG_CCSR		0x02
+#define CISREG_PRR		0x04
+#define CISREG_SCR		0x06
+#define CISREG_ESR		0x08
+#define CISREG_IOBASE_0		0x0a
+#define CISREG_IOBASE_1		0x0c
+#define CISREG_IOBASE_2		0x0e
+#define CISREG_IOBASE_3		0x10
+#define CISREG_IOSIZE		0x12
+
+/*
+ * Configuration Option Register
+ */
+#define COR_CONFIG_MASK		0x3f
+#define COR_MFC_CONFIG_MASK	0x38
+#define COR_FUNC_ENA		0x01
+#define COR_ADDR_DECODE		0x02
+#define COR_IREQ_ENA		0x04
+#define COR_LEVEL_REQ		0x40
+#define COR_SOFT_RESET		0x80
+
+/*
+ * Card Configuration and Status Register
+ */
+#define CCSR_INTR_ACK		0x01
+#define CCSR_INTR_PENDING	0x02
+#define CCSR_POWER_DOWN		0x04
+#define CCSR_AUDIO_ENA		0x08
+#define CCSR_IOIS8		0x20
+#define CCSR_SIGCHG_ENA		0x40
+#define CCSR_CHANGED		0x80
+
+/*
+ * Pin Replacement Register
+ */
+#define PRR_WP_STATUS		0x01
+#define PRR_READY_STATUS	0x02
+#define PRR_BVD2_STATUS		0x04
+#define PRR_BVD1_STATUS		0x08
+#define PRR_WP_EVENT		0x10
+#define PRR_READY_EVENT		0x20
+#define PRR_BVD2_EVENT		0x40
+#define PRR_BVD1_EVENT		0x80
+
+/*
+ * Socket and Copy Register
+ */
+#define SCR_SOCKET_NUM		0x0f
+#define SCR_COPY_NUM		0x70
+
+/*
+ * Extended Status Register
+ */
+#define ESR_REQ_ATTN_ENA	0x01
+#define ESR_REQ_ATTN		0x10
+
+/*
+ * CardBus Function Status Registers
+ */
+#define CBFN_EVENT		0x00
+#define CBFN_MASK		0x04
+#define CBFN_STATE		0x08
+#define CBFN_FORCE		0x0c
+
+/*
+ * These apply to all the CardBus function registers
+ */
+#define CBFN_WP			0x0001
+#define CBFN_READY		0x0002
+#define CBFN_BVD2		0x0004
+#define CBFN_BVD1		0x0008
+#define CBFN_GWAKE		0x0010
+#define CBFN_INTR		0x8000
+
+/*
+ * Extra bits in the Function Event Mask Register
+ */
+#define FEMR_BAM_ENA		0x0020
+#define FEMR_PWM_ENA		0x0040
+#define FEMR_WKUP_MASK		0x4000
+
+#endif /* _LINUX_CISREG_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cistpl.h linux/include/pcmcia/cistpl.h
--- v2.3.16/linux/include/pcmcia/cistpl.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/cistpl.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,583 @@
+/*
+ * cistpl.h 1.30 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CISTPL_H
+#define _LINUX_CISTPL_H
+
+#define CISTPL_NULL		0x00
+#define CISTPL_DEVICE		0x01
+#define CISTPL_LONGLINK_CB	0x02
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB	0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_CHECKSUM		0x10
+#define CISTPL_LONGLINK_A	0x11
+#define CISTPL_LONGLINK_C	0x12
+#define CISTPL_LINKTARGET	0x13
+#define CISTPL_NO_LINK		0x14
+#define CISTPL_VERS_1		0x15
+#define CISTPL_ALTSTR		0x16
+#define CISTPL_DEVICE_A		0x17
+#define CISTPL_JEDEC_C		0x18
+#define CISTPL_JEDEC_A		0x19
+#define CISTPL_CONFIG		0x1a
+#define CISTPL_CFTABLE_ENTRY	0x1b
+#define CISTPL_DEVICE_OC	0x1c
+#define CISTPL_DEVICE_OA	0x1d
+#define CISTPL_DEVICE_GEO	0x1e
+#define CISTPL_DEVICE_GEO_A	0x1f
+#define CISTPL_MANFID		0x20
+#define CISTPL_FUNCID		0x21
+#define CISTPL_FUNCE		0x22
+#define CISTPL_SWIL		0x23
+#define CISTPL_END		0xff
+/* Layer 2 tuples */
+#define CISTPL_VERS_2		0x40
+#define CISTPL_FORMAT		0x41
+#define CISTPL_GEOMETRY		0x42
+#define CISTPL_BYTEORDER	0x43
+#define CISTPL_DATE		0x44
+#define CISTPL_BATTERY		0x45
+/* Layer 3 tuples */
+#define CISTPL_ORG		0x46
+
+typedef struct cistpl_longlink_t {
+    u_int	addr;
+} cistpl_longlink_t;
+
+typedef struct cistpl_checksum_t {
+    u_short	addr;
+    u_short	len;
+    u_char	sum;
+} cistpl_checksum_t;
+
+#define CISTPL_MAX_FUNCTIONS	8
+#define CISTPL_MFC_ATTR		0x00
+#define CISTPL_MFC_COMMON	0x01
+
+typedef struct cistpl_longlink_mfc_t {
+    u_char	nfn;
+    struct {
+	u_char	space;
+	u_int	addr;
+    } fn[CISTPL_MAX_FUNCTIONS];
+} cistpl_longlink_mfc_t;
+
+#define CISTPL_MAX_ALTSTR_STRINGS	4
+
+typedef struct cistpl_altstr_t {
+    u_char	ns;
+    u_char	ofs[CISTPL_MAX_ALTSTR_STRINGS];
+    char	str[254];
+} cistpl_altstr_t;
+
+#define CISTPL_DTYPE_NULL	0x00
+#define CISTPL_DTYPE_ROM	0x01
+#define CISTPL_DTYPE_OTPROM	0x02
+#define CISTPL_DTYPE_EPROM	0x03
+#define CISTPL_DTYPE_EEPROM	0x04
+#define CISTPL_DTYPE_FLASH	0x05
+#define CISTPL_DTYPE_SRAM	0x06
+#define CISTPL_DTYPE_DRAM	0x07
+#define CISTPL_DTYPE_FUNCSPEC	0x0d
+#define CISTPL_DTYPE_EXTEND	0x0e
+
+#define CISTPL_MAX_DEVICES	4
+
+typedef struct cistpl_device_t {
+    u_char	ndev;
+    struct {
+	u_char 	type;
+	u_char	wp;
+	u_int	speed;
+	u_int	size;
+    } dev[CISTPL_MAX_DEVICES];
+} cistpl_device_t;
+
+#define CISTPL_DEVICE_MWAIT	0x01
+#define CISTPL_DEVICE_3VCC	0x02
+
+typedef struct cistpl_device_o_t {
+    u_char		flags;
+    cistpl_device_t	device;
+} cistpl_device_o_t;
+
+#define CISTPL_VERS_1_MAX_PROD_STRINGS	4
+
+typedef struct cistpl_vers_1_t {
+    u_char	major;
+    u_char	minor;
+    u_char	ns;
+    u_char	ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+    char	str[254];
+} cistpl_vers_1_t;
+
+typedef struct cistpl_jedec_t {
+    u_char	nid;
+    struct {
+	u_char	mfr;
+	u_char	info;
+    } id[CISTPL_MAX_DEVICES];
+} cistpl_jedec_t;
+
+typedef struct cistpl_manfid_t {
+    u_short	manf;
+    u_short	card;
+} cistpl_manfid_t;
+
+#define CISTPL_FUNCID_MULTI	0x00
+#define CISTPL_FUNCID_MEMORY	0x01
+#define CISTPL_FUNCID_SERIAL	0x02
+#define CISTPL_FUNCID_PARALLEL	0x03
+#define CISTPL_FUNCID_FIXED	0x04
+#define CISTPL_FUNCID_VIDEO	0x05
+#define CISTPL_FUNCID_NETWORK	0x06
+#define CISTPL_FUNCID_AIMS	0x07
+#define CISTPL_FUNCID_SCSI	0x08
+
+#define CISTPL_SYSINIT_POST	0x01
+#define CISTPL_SYSINIT_ROM	0x02
+
+typedef struct cistpl_funcid_t {
+    u_char	func;
+    u_char	sysinit;
+} cistpl_funcid_t;
+
+typedef struct cistpl_funce_t {
+    u_char	type;
+    u_char	data[0];
+} cistpl_funce_t;
+
+/*======================================================================
+
+    Modem Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_SERIAL_IF		0x00
+#define CISTPL_FUNCE_SERIAL_CAP		0x01
+#define CISTPL_FUNCE_SERIAL_SERV_DATA	0x02
+#define CISTPL_FUNCE_SERIAL_SERV_FAX	0x03
+#define CISTPL_FUNCE_SERIAL_SERV_VOICE	0x04
+#define CISTPL_FUNCE_SERIAL_CAP_DATA	0x05
+#define CISTPL_FUNCE_SERIAL_CAP_FAX	0x06
+#define CISTPL_FUNCE_SERIAL_CAP_VOICE	0x07
+#define CISTPL_FUNCE_SERIAL_IF_DATA	0x08
+#define CISTPL_FUNCE_SERIAL_IF_FAX	0x09
+#define CISTPL_FUNCE_SERIAL_IF_VOICE	0x0a
+
+/* UART identification */
+#define CISTPL_SERIAL_UART_8250		0x00
+#define CISTPL_SERIAL_UART_16450	0x01
+#define CISTPL_SERIAL_UART_16550	0x02
+#define CISTPL_SERIAL_UART_8251		0x03
+#define CISTPL_SERIAL_UART_8530		0x04
+#define CISTPL_SERIAL_UART_85230	0x05
+
+/* UART capabilities */
+#define CISTPL_SERIAL_UART_SPACE	0x01
+#define CISTPL_SERIAL_UART_MARK		0x02
+#define CISTPL_SERIAL_UART_ODD		0x04
+#define CISTPL_SERIAL_UART_EVEN		0x08
+#define CISTPL_SERIAL_UART_5BIT		0x01
+#define CISTPL_SERIAL_UART_6BIT		0x02
+#define CISTPL_SERIAL_UART_7BIT		0x04
+#define CISTPL_SERIAL_UART_8BIT		0x08
+#define CISTPL_SERIAL_UART_1STOP	0x10
+#define CISTPL_SERIAL_UART_MSTOP	0x20
+#define CISTPL_SERIAL_UART_2STOP	0x40
+
+typedef struct cistpl_serial_t {
+    u_char	uart_type;
+    u_char	uart_cap_0;
+    u_char	uart_cap_1;
+} cistpl_serial_t;
+
+typedef struct cistpl_modem_cap_t {
+    u_char	flow;
+    u_char	cmd_buf;
+    u_char	rcv_buf_0, rcv_buf_1, rcv_buf_2;
+    u_char	xmit_buf_0, xmit_buf_1, xmit_buf_2;
+} cistpl_modem_cap_t;
+
+#define CISTPL_SERIAL_MOD_103		0x01
+#define CISTPL_SERIAL_MOD_V21		0x02
+#define CISTPL_SERIAL_MOD_V23		0x04
+#define CISTPL_SERIAL_MOD_V22		0x08
+#define CISTPL_SERIAL_MOD_212A		0x10
+#define CISTPL_SERIAL_MOD_V22BIS	0x20
+#define CISTPL_SERIAL_MOD_V26		0x40
+#define CISTPL_SERIAL_MOD_V26BIS	0x80
+#define CISTPL_SERIAL_MOD_V27BIS	0x01
+#define CISTPL_SERIAL_MOD_V29		0x02
+#define CISTPL_SERIAL_MOD_V32		0x04
+#define CISTPL_SERIAL_MOD_V32BIS	0x08
+#define CISTPL_SERIAL_MOD_V34		0x10
+
+#define CISTPL_SERIAL_ERR_MNP2_4	0x01
+#define CISTPL_SERIAL_ERR_V42_LAPM	0x02
+
+#define CISTPL_SERIAL_CMPR_V42BIS	0x01
+#define CISTPL_SERIAL_CMPR_MNP5		0x02
+
+#define CISTPL_SERIAL_CMD_AT1		0x01
+#define CISTPL_SERIAL_CMD_AT2		0x02
+#define CISTPL_SERIAL_CMD_AT3		0x04
+#define CISTPL_SERIAL_CMD_MNP_AT	0x08
+#define CISTPL_SERIAL_CMD_V25BIS	0x10
+#define CISTPL_SERIAL_CMD_V25A		0x20
+#define CISTPL_SERIAL_CMD_DMCL		0x40
+
+typedef struct cistpl_data_serv_t {
+    u_char	max_data_0;
+    u_char	max_data_1;
+    u_char	modulation_0;
+    u_char	modulation_1;
+    u_char	error_control;
+    u_char	compression;
+    u_char	cmd_protocol;
+    u_char	escape;
+    u_char	encrypt;
+    u_char	misc_features;
+    u_char	ccitt_code[0];
+} cistpl_data_serv_t;
+
+typedef struct cistpl_fax_serv_t {
+    u_char	max_data_0;
+    u_char	max_data_1;
+    u_char	modulation;
+    u_char	encrypt;
+    u_char	features_0;
+    u_char	features_1;
+    u_char	ccitt_code[0];
+} cistpl_fax_serv_t;
+
+typedef struct cistpl_voice_serv_t {
+    u_char	max_data_0;
+    u_char	max_data_1;
+} cistpl_voice_serv_t;
+
+/*======================================================================
+
+    LAN Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_FUNCE_LAN_TECH		0x01
+#define CISTPL_FUNCE_LAN_SPEED		0x02
+#define CISTPL_FUNCE_LAN_MEDIA		0x03
+#define CISTPL_FUNCE_LAN_NODE_ID	0x04
+#define CISTPL_FUNCE_LAN_CONNECTOR	0x05
+
+/* LAN technologies */
+#define CISTPL_LAN_TECH_ARCNET		0x01
+#define CISTPL_LAN_TECH_ETHERNET	0x02
+#define CISTPL_LAN_TECH_TOKENRING	0x03
+#define CISTPL_LAN_TECH_LOCALTALK	0x04
+#define CISTPL_LAN_TECH_FDDI		0x05
+#define CISTPL_LAN_TECH_ATM		0x06
+#define CISTPL_LAN_TECH_WIRELESS	0x07
+
+typedef struct cistpl_lan_tech_t {
+    u_char	tech;
+} cistpl_lan_tech_t;
+
+typedef struct cistpl_lan_speed_t {
+    u_int	speed;
+} cistpl_lan_speed_t;
+
+/* LAN media definitions */
+#define CISTPL_LAN_MEDIA_UTP		0x01
+#define CISTPL_LAN_MEDIA_STP		0x02
+#define CISTPL_LAN_MEDIA_THIN_COAX	0x03
+#define CISTPL_LAN_MEDIA_THICK_COAX	0x04
+#define CISTPL_LAN_MEDIA_FIBER		0x05
+#define CISTPL_LAN_MEDIA_900MHZ		0x06
+#define CISTPL_LAN_MEDIA_2GHZ		0x07
+#define CISTPL_LAN_MEDIA_5GHZ		0x08
+#define CISTPL_LAN_MEDIA_DIFF_IR	0x09
+#define CISTPL_LAN_MEDIA_PTP_IR		0x0a
+
+typedef struct cistpl_lan_media_t {
+    u_char	media;
+} cistpl_lan_media_t;
+
+typedef struct cistpl_lan_node_id_t {
+    u_char	nb;
+    u_char	id[16];
+} cistpl_lan_node_id_t;
+
+typedef struct cistpl_lan_connector_t {
+    u_char	code;
+} cistpl_lan_connector_t;
+
+/*======================================================================
+
+    IDE Function Extension Tuples
+
+======================================================================*/
+
+#define CISTPL_IDE_INTERFACE		0x01
+
+typedef struct cistpl_ide_interface_t {
+    u_char	interface;
+} cistpl_ide_interface_t;
+
+/* First feature byte */
+#define CISTPL_IDE_SILICON		0x04
+#define CISTPL_IDE_UNIQUE		0x08
+#define CISTPL_IDE_DUAL			0x10
+
+/* Second feature byte */
+#define CISTPL_IDE_HAS_SLEEP		0x01
+#define CISTPL_IDE_HAS_STANDBY		0x02
+#define CISTPL_IDE_HAS_IDLE		0x04
+#define CISTPL_IDE_LOW_POWER		0x08
+#define CISTPL_IDE_REG_INHIBIT		0x10
+#define CISTPL_IDE_HAS_INDEX		0x20
+#define CISTPL_IDE_IOIS16		0x40
+
+typedef struct cistpl_ide_feature_t {
+    u_char	feature1;
+    u_char	feature2;
+} cistpl_ide_feature_t;
+
+#define CISTPL_FUNCE_IDE_IFACE		0x01
+#define CISTPL_FUNCE_IDE_MASTER		0x02
+#define CISTPL_FUNCE_IDE_SLAVE		0x03
+
+/*======================================================================
+
+    Configuration Table Entries
+
+======================================================================*/
+
+#define CISTPL_BAR_SPACE	0x07
+#define CISTPL_BAR_SPACE_IO	0x10
+#define CISTPL_BAR_PREFETCH	0x20
+#define CISTPL_BAR_CACHEABLE	0x40
+#define CISTPL_BAR_1MEG_MAP	0x80
+
+typedef struct cistpl_bar_t {
+    u_char	attr;
+    u_int	size;
+} cistpl_bar_t;
+
+typedef struct cistpl_config_t {
+    u_char	last_idx;
+    u_int	base;
+    u_int	rmask[4];
+    u_char	subtuples;
+} cistpl_config_t;
+
+/* These are bits in the 'present' field, and indices in 'param' */
+#define CISTPL_POWER_VNOM	0
+#define CISTPL_POWER_VMIN	1
+#define CISTPL_POWER_VMAX	2
+#define CISTPL_POWER_ISTATIC	3
+#define CISTPL_POWER_IAVG	4
+#define CISTPL_POWER_IPEAK	5
+#define CISTPL_POWER_IDOWN	6
+
+#define CISTPL_POWER_HIGHZ_OK	0x01
+#define CISTPL_POWER_HIGHZ_REQ	0x02
+
+typedef struct cistpl_power_t {
+    u_char	present;
+    u_char	flags;
+    u_int	param[7];
+} cistpl_power_t;
+
+typedef struct cistpl_timing_t {
+    u_int	wait, waitscale;
+    u_int	ready, rdyscale;
+    u_int	reserved, rsvscale;
+} cistpl_timing_t;
+
+#define CISTPL_IO_LINES_MASK	0x1f
+#define CISTPL_IO_8BIT		0x20
+#define CISTPL_IO_16BIT		0x40
+#define CISTPL_IO_RANGE		0x80
+
+#define CISTPL_IO_MAX_WIN	16
+
+typedef struct cistpl_io_t {
+    u_char	flags;
+    u_char	nwin;
+    struct {
+	u_int	base;
+	u_int	len;
+    } win[CISTPL_IO_MAX_WIN];
+} cistpl_io_t;
+
+typedef struct cistpl_irq_t {
+    u_int	IRQInfo1;
+    u_int	IRQInfo2;
+} cistpl_irq_t;
+
+#define CISTPL_MEM_MAX_WIN	8
+
+typedef struct cistpl_mem_t {
+    u_char	flags;
+    u_char	nwin;
+    struct {
+	u_int	len;
+	u_int	card_addr;
+	u_int	host_addr;
+    } win[CISTPL_MEM_MAX_WIN];
+} cistpl_mem_t;
+
+#define CISTPL_CFTABLE_DEFAULT		0x0001
+#define CISTPL_CFTABLE_BVDS		0x0002
+#define CISTPL_CFTABLE_WP		0x0004
+#define CISTPL_CFTABLE_RDYBSY		0x0008
+#define CISTPL_CFTABLE_MWAIT		0x0010
+#define CISTPL_CFTABLE_AUDIO		0x0800
+#define CISTPL_CFTABLE_READONLY		0x1000
+#define CISTPL_CFTABLE_PWRDOWN		0x2000
+
+typedef struct cistpl_cftable_entry_t {
+    u_char		index;
+    u_short		flags;
+    u_char		interface;
+    cistpl_power_t	vcc, vpp1, vpp2;
+    cistpl_timing_t	timing;
+    cistpl_io_t		io;
+    cistpl_irq_t	irq;
+    cistpl_mem_t	mem;
+    u_char		subtuples;
+} cistpl_cftable_entry_t;
+
+#define CISTPL_CFTABLE_MASTER		0x000100
+#define CISTPL_CFTABLE_INVALIDATE	0x000200
+#define CISTPL_CFTABLE_VGA_PALETTE	0x000400
+#define CISTPL_CFTABLE_PARITY		0x000800
+#define CISTPL_CFTABLE_WAIT		0x001000
+#define CISTPL_CFTABLE_SERR		0x002000
+#define CISTPL_CFTABLE_FAST_BACK	0x004000
+#define CISTPL_CFTABLE_BINARY_AUDIO	0x010000
+#define CISTPL_CFTABLE_PWM_AUDIO	0x020000
+
+typedef struct cistpl_cftable_entry_cb_t {
+    u_char		index;
+    u_int		flags;
+    cistpl_power_t	vcc, vpp1, vpp2;
+    u_char		io;
+    cistpl_irq_t	irq;
+    u_char		mem;
+    u_char		subtuples;
+} cistpl_cftable_entry_cb_t;
+
+typedef struct cistpl_device_geo_t {
+    u_char		ngeo;
+    struct {
+	u_char		buswidth;
+	u_int		erase_block;
+	u_int		read_block;
+	u_int		write_block;
+	u_int		partition;
+	u_int		interleave;
+    } geo[CISTPL_MAX_DEVICES];
+} cistpl_device_geo_t;
+
+typedef struct cistpl_vers_2_t {
+    u_char	vers;
+    u_char	comply;
+    u_short	dindex;
+    u_char	vspec8, vspec9;
+    u_char	nhdr;
+    u_char	vendor, info;
+    char	str[244];
+} cistpl_vers_2_t;
+
+typedef struct cistpl_org_t {
+    u_char	data_org;
+    char	desc[30];
+} cistpl_org_t;
+
+#define CISTPL_ORG_FS		0x00
+#define CISTPL_ORG_APPSPEC	0x01
+#define CISTPL_ORG_XIP		0x02
+
+typedef union cisparse_t {
+    cistpl_device_t		device;
+    cistpl_checksum_t		checksum;
+    cistpl_longlink_t		longlink;
+    cistpl_longlink_mfc_t	longlink_mfc;
+    cistpl_vers_1_t		version_1;
+    cistpl_altstr_t		altstr;
+    cistpl_jedec_t		jedec;
+    cistpl_manfid_t		manfid;
+    cistpl_funcid_t		funcid;
+    cistpl_funce_t		funce;
+    cistpl_bar_t		bar;
+    cistpl_config_t		config;
+    cistpl_cftable_entry_t	cftable_entry;
+    cistpl_cftable_entry_cb_t	cftable_entry_cb;
+    cistpl_device_geo_t		device_geo;
+    cistpl_vers_2_t		vers_2;
+    cistpl_org_t		org;
+} cisparse_t;
+
+typedef struct tuple_t {
+    u_int	Attributes;
+    cisdata_t 	DesiredTuple;
+    u_int	Flags;		/* internal use */
+    u_int	LinkOffset;	/* internal use */
+    u_int	CISOffset;	/* internal use */
+    cisdata_t	TupleCode;
+    cisdata_t	TupleLink;
+    cisdata_t	TupleOffset;
+    cisdata_t	TupleDataMax;
+    cisdata_t	TupleDataLen;
+    cisdata_t	*TupleData;
+} tuple_t;
+
+/* Special cisdata_t value */
+#define RETURN_FIRST_TUPLE	0xff
+
+/* Attributes for tuple calls */
+#define TUPLE_RETURN_LINK	0x01
+#define TUPLE_RETURN_COMMON	0x02
+
+/* For ValidateCIS */
+typedef struct cisinfo_t {
+    u_int	Chains;
+} cisinfo_t;
+
+#define CISTPL_MAX_CIS_SIZE	0x200
+
+/* For ReplaceCIS */
+typedef struct cisdump_t {
+    u_int	Length;
+    cisdata_t	Data[CISTPL_MAX_CIS_SIZE];
+} cisdump_t;
+
+#endif /* LINUX_CISTPL_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cs.h linux/include/pcmcia/cs.h
--- v2.3.16/linux/include/pcmcia/cs.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/cs.h	Tue Sep  7 11:46:55 1999
@@ -0,0 +1,468 @@
+/*
+ * cs.h 1.67 1999/09/02 18:34:59
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_H
+#define _LINUX_CS_H
+
+/* For AccessConfigurationRegister */
+typedef struct conf_reg_t {
+    u_char	Function;
+    u_int	Action;
+    off_t	Offset;
+    u_int	Value;
+} conf_reg_t;
+
+/* Actions */
+#define CS_READ		1
+#define CS_WRITE	2
+
+/* for AdjustResourceInfo */
+typedef struct adjust_t {
+    u_int	Action;
+    u_int	Resource;
+    u_int	Attributes;
+    union {
+	struct memory {
+	    u_long	Base;
+	    u_long	Size;
+	} memory;
+	struct io {
+	    ioaddr_t	BasePort;
+	    ioaddr_t	NumPorts;
+	    u_int	IOAddrLines;
+	} io;
+	struct irq {
+	    u_int	IRQ;
+	} irq;
+    } resource;
+} adjust_t;
+
+/* Action field */
+#define REMOVE_MANAGED_RESOURCE		1
+#define ADD_MANAGED_RESOURCE		2
+#define GET_FIRST_MANAGED_RESOURCE	3
+#define GET_NEXT_MANAGED_RESOURCE	4
+/* Resource field */
+#define RES_MEMORY_RANGE		1
+#define RES_IO_RANGE			2
+#define RES_IRQ				3
+/* Attribute field */
+#define RES_IRQ_TYPE			0x03
+#define RES_IRQ_TYPE_EXCLUSIVE		0
+#define RES_IRQ_TYPE_TIME		1
+#define RES_IRQ_TYPE_DYNAMIC		2
+#define RES_IRQ_CSC			0x04
+#define RES_SHARED			0x08
+#define RES_RESERVED			0x10
+#define RES_ALLOCATED			0x20
+#define RES_REMOVED			0x40
+
+typedef struct servinfo_t {
+    char	Signature[2];
+    u_int	Count;
+    u_int	Revision;
+    u_int	CSLevel;
+    char	*VendorString;
+} servinfo_t;
+
+typedef struct event_callback_args_t {
+    client_handle_t client_handle;
+    void	*info;
+    void	*mtdrequest;
+    void	*buffer;
+    void	*misc;
+    void	*client_data;
+    struct bus_operations *bus;
+} event_callback_args_t;
+
+/* for GetConfigurationInfo */
+typedef struct config_info_t {
+    u_char	Function;
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+    u_int	IntType;
+    u_int	ConfigBase;
+    u_char	Status, Pin, Copy, Option, ExtStatus;
+    u_int	Present;
+    u_int	CardValues;
+    u_int	AssignedIRQ;
+    u_int	IRQAttributes;
+    ioaddr_t	BasePort1;
+    ioaddr_t	NumPorts1;
+    u_int	Attributes1;
+    ioaddr_t	BasePort2;
+    ioaddr_t	NumPorts2;
+    u_int	Attributes2;
+    u_int	IOAddrLines;
+} config_info_t;
+
+/* For CardValues field */
+#define CV_OPTION_VALUE		0x01
+#define CV_STATUS_VALUE		0x02
+#define CV_PIN_REPLACEMENT	0x04
+#define CV_COPY_VALUE		0x08
+#define CV_EXT_STATUS		0x10
+
+/* For GetFirst/NextClient */
+typedef struct client_req_t {
+    socket_t	Socket;
+    u_int	Attributes;
+} client_req_t;
+
+#define CLIENT_THIS_SOCKET	0x01
+
+/* For RegisterClient */
+typedef struct client_reg_t {
+    dev_info_t	*dev_info;
+    u_int	Attributes;
+    u_int	EventMask;
+    int		(*event_handler)(event_t event, int priority,
+				 event_callback_args_t *);
+    event_callback_args_t event_callback_args;
+    u_int	Version;
+} client_reg_t;
+
+/* ModifyConfiguration */
+typedef struct modconf_t {
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+} modconf_t;
+
+/* Attributes for ModifyConfiguration */
+#define CONF_IRQ_CHANGE_VALID	0x100
+#define CONF_VCC_CHANGE_VALID	0x200
+#define CONF_VPP1_CHANGE_VALID	0x400
+#define CONF_VPP2_CHANGE_VALID	0x800
+
+/* For RequestConfiguration */
+typedef struct config_req_t {
+    u_int	Attributes;
+    u_int	Vcc, Vpp1, Vpp2;
+    u_int	IntType;
+    u_int	ConfigBase;
+    u_char	Status, Pin, Copy, ExtStatus;
+    u_char	ConfigIndex;
+    u_int	Present;
+} config_req_t;
+
+/* Attributes for RequestConfiguration */
+#define CONF_ENABLE_IRQ		0x01
+#define CONF_ENABLE_DMA		0x02
+#define CONF_ENABLE_SPKR	0x04
+#define CONF_VALID_CLIENT	0x100
+
+/* IntType field */
+#define INT_MEMORY		0x01
+#define INT_MEMORY_AND_IO	0x02
+#define INT_CARDBUS		0x04
+
+/* For RequestIO and ReleaseIO */
+typedef struct io_req_t {
+    ioaddr_t	BasePort1;
+    ioaddr_t	NumPorts1;
+    u_int	Attributes1;
+    ioaddr_t	BasePort2;
+    ioaddr_t	NumPorts2;
+    u_int	Attributes2;
+    u_int	IOAddrLines;
+} io_req_t;
+
+/* Attributes for RequestIO and ReleaseIO */
+#define IO_SHARED		0x01
+#define IO_FIRST_SHARED		0x02
+#define IO_FORCE_ALIAS_ACCESS	0x04
+#define IO_DATA_PATH_WIDTH	0x18
+#define IO_DATA_PATH_WIDTH_8	0x00
+#define IO_DATA_PATH_WIDTH_16	0x08
+#define IO_DATA_PATH_WIDTH_AUTO	0x10
+
+/* For RequestIRQ and ReleaseIRQ */
+typedef struct irq_req_t {
+    u_int	Attributes;
+    u_int	AssignedIRQ;
+    u_int	IRQInfo1, IRQInfo2;
+    void	*Handler;
+    void	*Instance;
+} irq_req_t;
+
+/* Attributes for RequestIRQ and ReleaseIRQ */
+#define IRQ_TYPE			0x03
+#define IRQ_TYPE_EXCLUSIVE		0x00
+#define IRQ_TYPE_TIME			0x01
+#define IRQ_TYPE_DYNAMIC_SHARING	0x02
+#define IRQ_FORCED_PULSE		0x04
+#define IRQ_FIRST_SHARED		0x08
+#define IRQ_HANDLE_PRESENT		0x10
+#define IRQ_PULSE_ALLOCATED		0x100
+
+/* Bits in IRQInfo1 field */
+#define IRQ_MASK		0x0f
+#define IRQ_NMI_ID		0x01
+#define IRQ_IOCK_ID		0x02
+#define IRQ_BERR_ID		0x04
+#define IRQ_VEND_ID		0x08
+#define IRQ_INFO2_VALID		0x10
+#define IRQ_LEVEL_ID		0x20
+#define IRQ_PULSE_ID		0x40
+#define IRQ_SHARE_ID		0x80
+
+typedef struct eventmask_t {
+    u_int	Attributes;
+    u_int	EventMask;
+} eventmask_t;
+
+#define CONF_EVENT_MASK_VALID	0x01
+
+/* Configuration registers present */
+#define PRESENT_OPTION		0x001
+#define PRESENT_STATUS		0x002
+#define PRESENT_PIN_REPLACE	0x004
+#define PRESENT_COPY		0x008
+#define PRESENT_EXT_STATUS	0x010
+#define PRESENT_IOBASE_0	0x020
+#define PRESENT_IOBASE_1	0x040
+#define PRESENT_IOBASE_2	0x080
+#define PRESENT_IOBASE_3	0x100
+#define PRESENT_IOSIZE		0x200
+
+/* Attributes for Request/GetConfiguration */
+#define CONF_ENABLE_IRQ		0x01
+#define EXCLUSIVE_USE		0x02
+#define VALID_CLIENT		0x04
+
+/* For GetMemPage, MapMemPage */
+typedef struct memreq_t {
+    u_int	CardOffset;
+    page_t	Page;
+} memreq_t;
+
+/* For ModifyWindow */
+typedef struct modwin_t {
+    u_int	Attributes;
+    u_int	AccessSpeed;
+} modwin_t;
+
+/* For RequestWindow */
+typedef struct win_req_t {
+    u_int	Attributes;
+    u_long	Base;
+    u_int	Size;
+    u_int	AccessSpeed;
+} win_req_t;
+
+/* Attributes for RequestWindow */
+#define WIN_ADDR_SPACE		0x0001
+#define WIN_ADDR_SPACE_MEM	0x0000
+#define WIN_ADDR_SPACE_IO	0x0001
+#define WIN_MEMORY_TYPE		0x0002
+#define WIN_MEMORY_TYPE_CM	0x0000
+#define WIN_MEMORY_TYPE_AM	0x0002
+#define WIN_ENABLE		0x0004
+#define WIN_DATA_WIDTH		0x0018
+#define WIN_DATA_WIDTH_8	0x0000
+#define WIN_DATA_WIDTH_16	0x0008
+#define WIN_DATA_WIDTH_32	0x0010
+#define WIN_PAGED		0x0020
+#define WIN_SHARED		0x0040
+#define WIN_FIRST_SHARED	0x0080
+#define WIN_USE_WAIT		0x0100
+#define WIN_MAP_BELOW_1MB	0x0400
+#define WIN_PREFETCH		0x0800
+#define WIN_CACHEABLE		0x1000
+#define WIN_BAR_MASK		0xe000
+#define WIN_BAR_SHIFT		13
+
+/* Attributes for RegisterClient */
+#define INFO_MASTER_CLIENT	0x01
+#define INFO_IO_CLIENT		0x02
+#define INFO_MTD_CLIENT		0x04
+#define INFO_MEM_CLIENT		0x08
+#define MAX_NUM_CLIENTS		3
+
+#define INFO_CARD_SHARE		0x10
+#define INFO_CARD_EXCL		0x20
+
+typedef struct cs_status_t {
+    u_char	Function;
+    event_t 	CardState;
+    event_t	SocketState;
+} cs_status_t;
+
+typedef struct error_info_t {
+    int		func;
+    int		retcode;
+} error_info_t;
+
+/* Special stuff for binding drivers to sockets */
+typedef struct bind_req_t {
+    socket_t	Socket;
+    u_char	Function;
+    dev_info_t	*dev_info;
+} bind_req_t;
+
+/* Flag to bind to all functions */
+#define BIND_FN_ALL	0xff
+
+typedef struct mtd_bind_t {
+    socket_t	Socket;
+    u_int	Attributes;
+    u_int	CardOffset;
+    dev_info_t	*dev_info;
+} mtd_bind_t;
+
+/* Events */
+#define CS_EVENT_PRI_LOW		0
+#define CS_EVENT_PRI_HIGH		1
+
+#define CS_EVENT_WRITE_PROTECT		0x000001
+#define CS_EVENT_CARD_LOCK		0x000002
+#define CS_EVENT_CARD_INSERTION		0x000004
+#define CS_EVENT_CARD_REMOVAL		0x000008
+#define CS_EVENT_BATTERY_DEAD		0x000010
+#define CS_EVENT_BATTERY_LOW		0x000020
+#define CS_EVENT_READY_CHANGE		0x000040
+#define CS_EVENT_CARD_DETECT		0x000080
+#define CS_EVENT_RESET_REQUEST		0x000100
+#define CS_EVENT_RESET_PHYSICAL		0x000200
+#define CS_EVENT_CARD_RESET		0x000400
+#define CS_EVENT_REGISTRATION_COMPLETE	0x000800
+#define CS_EVENT_RESET_COMPLETE		0x001000
+#define CS_EVENT_PM_SUSPEND		0x002000
+#define CS_EVENT_PM_RESUME		0x004000
+#define CS_EVENT_INSERTION_REQUEST	0x008000
+#define CS_EVENT_EJECTION_REQUEST	0x010000
+#define CS_EVENT_MTD_REQUEST		0x020000
+#define CS_EVENT_ERASE_COMPLETE		0x040000
+#define CS_EVENT_REQUEST_ATTENTION	0x080000
+#define CS_EVENT_CB_DETECT		0x100000
+#define CS_EVENT_3VCARD			0x200000
+#define CS_EVENT_XVCARD			0x400000
+
+/* Return codes */
+#define CS_SUCCESS		0x00
+#define CS_BAD_ADAPTER		0x01
+#define CS_BAD_ATTRIBUTE	0x02
+#define CS_BAD_BASE		0x03
+#define CS_BAD_EDC		0x04
+#define CS_BAD_IRQ		0x06
+#define CS_BAD_OFFSET		0x07
+#define CS_BAD_PAGE		0x08
+#define CS_READ_FAILURE		0x09
+#define CS_BAD_SIZE		0x0a
+#define CS_BAD_SOCKET		0x0b
+#define CS_BAD_TYPE		0x0d
+#define CS_BAD_VCC		0x0e
+#define CS_BAD_VPP		0x0f
+#define CS_BAD_WINDOW		0x11
+#define CS_WRITE_FAILURE	0x12
+#define CS_NO_CARD		0x14
+#define CS_UNSUPPORTED_FUNCTION	0x15
+#define CS_UNSUPPORTED_MODE	0x16
+#define CS_BAD_SPEED		0x17
+#define CS_BUSY			0x18
+#define CS_GENERAL_FAILURE	0x19
+#define CS_WRITE_PROTECTED	0x1a
+#define CS_BAD_ARG_LENGTH	0x1b
+#define CS_BAD_ARGS		0x1c
+#define CS_CONFIGURATION_LOCKED	0x1d
+#define CS_IN_USE		0x1e
+#define CS_NO_MORE_ITEMS	0x1f
+#define CS_OUT_OF_RESOURCE	0x20
+#define CS_BAD_HANDLE		0x21
+
+#define CS_BAD_TUPLE		0x40
+
+#ifdef __KERNEL__
+
+/*
+ *  Calls to set up low-level "Socket Services" drivers
+ */
+
+typedef int (*ss_entry_t)(u_int sock, u_int cmd, void *arg);
+extern int register_ss_entry(int nsock, ss_entry_t entry);
+extern void unregister_ss_entry(ss_entry_t entry);
+
+/*
+ *  The main Card Services entry point
+ */
+
+enum service {
+    AccessConfigurationRegister, AddSocketServices,
+    AdjustResourceInfo, CheckEraseQueue, CloseMemory, CopyMemory,
+    DeregisterClient, DeregisterEraseQueue, GetCardServicesInfo,
+    GetClientInfo, GetConfigurationInfo, GetEventMask,
+    GetFirstClient, GetFirstPartion, GetFirstRegion, GetFirstTuple,
+    GetNextClient, GetNextPartition, GetNextRegion, GetNextTuple,
+    GetStatus, GetTupleData, MapLogSocket, MapLogWindow, MapMemPage,
+    MapPhySocket, MapPhyWindow, ModifyConfiguration, ModifyWindow,
+    OpenMemory, ParseTuple, ReadMemory, RegisterClient,
+    RegisterEraseQueue, RegisterMTD, RegisterTimer,
+    ReleaseConfiguration, ReleaseExclusive, ReleaseIO, ReleaseIRQ,
+    ReleaseSocketMask, ReleaseWindow, ReplaceSocketServices,
+    RequestConfiguration, RequestExclusive, RequestIO, RequestIRQ,
+    RequestSocketMask, RequestWindow, ResetCard, ReturnSSEntry,
+    SetEventMask, SetRegion, ValidateCIS, VendorSpecific,
+    WriteMemory, BindDevice, BindMTD, ReportError,
+    SuspendCard, ResumeCard, EjectCard, InsertCard, ReplaceCIS,
+    GetFirstWindow, GetNextWindow, GetMemPage
+};
+
+#ifdef IN_CARD_SERVICES
+extern int CardServices(int func, void *a1, void *a2, void *a3);
+#else
+extern int CardServices(int func, ...);
+#endif
+
+#ifdef __BEOS__
+#define SS_MODULE_NAME(s)	("busses/pcmcia/" s "/v1")
+#define MTD_MODULE_NAME(s)	("busses/pcmcia/" s "/v1")
+#define CS_CLIENT_MODULE_NAME	"bus_managers/pcmcia_cs/client/v1"
+typedef struct cs_client_module_info {
+    bus_manager_info	binfo;
+    int (*_CardServices)(int, ...);
+    int (*_MTDHelperEntry)(int, ...);
+    void (*_add_timer)(struct timer_list *);
+    void (*_del_timer)(struct timer_list *);
+} cs_client_module_info;
+#define CS_SOCKET_MODULE_NAME "bus_managers/pcmcia_cs/socket/v1"
+typedef struct cs_socket_module_info {
+    bus_manager_info	binfo;
+    int (*_register_ss_entry)(int, ss_entry_t);
+    void (*_unregister_ss_entry)(ss_entry_t);
+    void (*_add_timer)(struct timer_list *);
+    void (*_del_timer)(struct timer_list *);
+    int (*register_resource)(int, u_long, u_long);
+    int (*release_resource)(int, u_long, u_long);
+    int (*check_resource)(int, u_long, u_long);
+} cs_socket_module_info;
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_CS_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/cs_types.h linux/include/pcmcia/cs_types.h
--- v2.3.16/linux/include/pcmcia/cs_types.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/cs_types.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,61 @@
+/*
+ * cs_types.h 1.15 1999/08/28 04:12:32
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_CS_TYPES_H
+#define _LINUX_CS_TYPES_H
+
+#ifdef __linux__
+#include <linux/types.h>
+#endif
+
+typedef u_short	socket_t;
+typedef u_short	ioaddr_t;
+typedef u_int	event_t;
+typedef u_char	cisdata_t;
+typedef u_short	page_t;
+
+struct client_t;
+typedef struct client_t *client_handle_t;
+
+struct window_t;
+typedef struct window_t *window_handle_t;
+
+struct region_t;
+typedef struct region_t *memory_handle_t;
+
+struct eraseq_t;
+typedef struct eraseq_t *eraseq_handle_t;
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+typedef char dev_info_t[DEV_NAME_LEN];
+
+#endif /* _LINUX_CS_TYPES_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/driver_ops.h linux/include/pcmcia/driver_ops.h
--- v2.3.16/linux/include/pcmcia/driver_ops.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/driver_ops.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,82 @@
+/*
+ * driver_ops.h 1.13 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DRIVER_OPS_H
+#define _LINUX_DRIVER_OPS_H
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN	32
+#endif
+
+#ifdef __KERNEL__
+
+typedef struct dev_node_t {
+    char		dev_name[DEV_NAME_LEN];
+    u_short		major, minor;
+    struct dev_node_t	*next;
+} dev_node_t;
+
+typedef struct dev_locator_t {
+    enum { LOC_ISA, LOC_PCI } bus;
+    union {
+	struct {
+	    u_short	io_base_1, io_base_2;
+	    u_long	mem_base;
+	    u_char	irq, dma;
+	} isa;
+	struct {
+	    u_char	bus;
+	    u_char	devfn;
+	} pci;
+    } b;
+} dev_locator_t;
+
+typedef struct driver_operations {
+    char		*name;
+    dev_node_t		*(*attach) (dev_locator_t *loc);
+    void		(*suspend) (dev_node_t *dev);
+    void		(*resume) (dev_node_t *dev);
+    void		(*detach) (dev_node_t *dev);
+} driver_operations;
+
+int register_driver(struct driver_operations *ops);
+void unregister_driver(struct driver_operations *ops);
+
+#ifdef __BEOS__
+#define CB_ENABLER_MODULE_NAME	"bus_managers/cb_enabler/v1"
+typedef struct cb_enabler_module_info {
+    bus_manager_info	binfo;
+    int (*register_driver)(struct driver_operations *ops);
+    void (*unregister_driver)(struct driver_operations *ops);
+} cb_enabler_module_info;
+#endif /* __BEOS__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DRIVER_OPS_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ds.h linux/include/pcmcia/ds.h
--- v2.3.16/linux/include/pcmcia/ds.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/ds.h	Tue Sep  7 11:46:55 1999
@@ -0,0 +1,163 @@
+/*
+ * ds.h 1.54 1999/09/03 16:44:49
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_DS_H
+#define _LINUX_DS_H
+
+#include <pcmcia/driver_ops.h>
+#include <pcmcia/bulkmem.h>
+
+typedef struct tuple_parse_t {
+    tuple_t		tuple;
+    cisdata_t		data[255];
+    cisparse_t		parse;
+} tuple_parse_t;
+
+typedef struct win_info_t {
+    window_handle_t	handle;
+    win_req_t		window;
+    memreq_t		map;
+} win_info_t;
+    
+typedef struct bind_info_t {
+    dev_info_t		dev_info;
+    u_char		function;
+    struct dev_link_t	*instance;
+    char		name[DEV_NAME_LEN];
+    u_short		major, minor;
+    void		*next;
+} bind_info_t;
+
+typedef struct mtd_info_t {
+    dev_info_t		dev_info;
+    u_int		Attributes;
+    u_int		CardOffset;
+} mtd_info_t;
+
+typedef union ds_ioctl_arg_t {
+    servinfo_t		servinfo;
+    adjust_t		adjust;
+    config_info_t	config;
+    tuple_t		tuple;
+    tuple_parse_t	tuple_parse;
+    client_req_t	client_req;
+    cs_status_t		status;
+    conf_reg_t		conf_reg;
+    cisinfo_t		cisinfo;
+    region_info_t	region;
+    bind_info_t		bind_info;
+    mtd_info_t		mtd_info;
+    win_info_t		win_info;
+    cisdump_t		cisdump;
+} ds_ioctl_arg_t;
+
+#define DS_GET_CARD_SERVICES_INFO	_IOR ('d', 1, servinfo_t)
+#define DS_ADJUST_RESOURCE_INFO		_IOWR('d', 2, adjust_t)
+#define DS_GET_CONFIGURATION_INFO	_IOWR('d', 3, config_info_t)
+#define DS_GET_FIRST_TUPLE		_IOWR('d', 4, tuple_t)
+#define DS_GET_NEXT_TUPLE		_IOWR('d', 5, tuple_t)
+#define DS_GET_TUPLE_DATA		_IOWR('d', 6, tuple_parse_t)
+#define DS_PARSE_TUPLE			_IOWR('d', 7, tuple_parse_t)
+#define DS_RESET_CARD			_IO  ('d', 8)
+#define DS_GET_STATUS			_IOWR('d', 9, cs_status_t)
+#define DS_ACCESS_CONFIGURATION_REGISTER _IOWR('d', 10, conf_reg_t)
+#define DS_VALIDATE_CIS			_IOR ('d', 11, cisinfo_t)
+#define DS_SUSPEND_CARD			_IO  ('d', 12)
+#define DS_RESUME_CARD			_IO  ('d', 13)
+#define DS_EJECT_CARD			_IO  ('d', 14)
+#define DS_INSERT_CARD			_IO  ('d', 15)
+#define DS_GET_FIRST_REGION		_IOWR('d', 16, region_info_t)
+#define DS_GET_NEXT_REGION		_IOWR('d', 17, region_info_t)
+#define DS_REPLACE_CIS			_IOWR('d', 18, cisdump_t)
+#define DS_GET_FIRST_WINDOW		_IOR ('d', 19, win_info_t)
+#define DS_GET_NEXT_WINDOW		_IOWR('d', 20, win_info_t)
+#define DS_GET_MEM_PAGE			_IOWR('d', 21, win_info_t)
+
+#define DS_BIND_REQUEST			_IOWR('d', 60, bind_info_t)
+#define DS_GET_DEVICE_INFO		_IOWR('d', 61, bind_info_t) 
+#define DS_GET_NEXT_DEVICE		_IOWR('d', 62, bind_info_t) 
+#define DS_UNBIND_REQUEST		_IOW ('d', 63, bind_info_t)
+#define DS_BIND_MTD			_IOWR('d', 64, mtd_info_t)
+
+#ifdef __KERNEL__
+
+typedef struct dev_link_t {
+    dev_node_t		*dev;
+    u_int		state, open;
+    wait_queue_head_t	pending;
+    struct timer_list	release;
+    client_handle_t	handle;
+    io_req_t		io;
+    irq_req_t		irq;
+    config_req_t	conf;
+    window_handle_t	win;
+    void		*priv;
+    struct dev_link_t	*next;
+} dev_link_t;
+
+/* Flags for device state */
+#define DEV_PRESENT		0x01
+#define DEV_CONFIG		0x02
+#define DEV_STALE_CONFIG	0x04	/* release on close */
+#define DEV_STALE_LINK		0x08	/* detach on release */
+#define DEV_CONFIG_PENDING	0x10
+#define DEV_RELEASE_PENDING	0x20
+#define DEV_SUSPEND		0x40
+#define DEV_BUSY		0x80
+
+#define DEV_OK(l) \
+    ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
+
+int register_pccard_driver(dev_info_t *dev_info,
+			   dev_link_t *(*attach)(void),
+			   void (*detach)(dev_link_t *));
+
+int unregister_pccard_driver(dev_info_t *dev_info);
+
+#define register_pcmcia_driver register_pccard_driver
+#define unregister_pcmcia_driver unregister_pccard_driver
+
+#ifdef __BEOS__
+#define DS_MODULE_NAME "bus_managers/pcmcia_ds/v1"
+typedef struct ds_module_info {
+    bus_manager_info binfo;
+    int (*_register_pccard_driver)(dev_info_t *,
+				   dev_link_t *(*)(void),
+				   void (*)(dev_link_t *));
+    int (*_unregister_pccard_driver)(dev_info_t *);
+    struct driver_info_t **root_driver;
+    int *sockets;
+    struct socket_info_t **socket_table;
+    sem_id *list_sem;
+} ds_module_info;
+#endif /* __BEOS__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_DS_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ftl.h linux/include/pcmcia/ftl.h
--- v2.3.16/linux/include/pcmcia/ftl.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/ftl.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,73 @@
+/*
+ * ftl.h 1.6 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_FTL_H
+#define _LINUX_FTL_H
+
+typedef struct erase_unit_header_t {
+    u_char	LinkTargetTuple[5];
+    u_char	DataOrgTuple[10];
+    u_char	NumTransferUnits;
+    u_int	EraseCount;
+    u_short	LogicalEUN;
+    u_char	BlockSize;
+    u_char	EraseUnitSize;
+    u_short	FirstPhysicalEUN;
+    u_short	NumEraseUnits;
+    u_int	FormattedSize;
+    u_int	FirstVMAddress;
+    u_short	NumVMPages;
+    u_char	Flags;
+    u_char	Code;
+    u_int	SerialNumber;
+    u_int	AltEUHOffset;
+    u_int	BAMOffset;
+    u_char	Reserved[12];
+    u_char	EndTuple[2];
+} erase_unit_header_t;
+
+/* Flags in erase_unit_header_t */
+#define HIDDEN_AREA		0x01
+#define REVERSE_POLARITY	0x02
+#define DOUBLE_BAI		0x04
+
+/* Definitions for block allocation information */
+
+#define BLOCK_FREE(b)		((b) == 0xffffffff)
+#define BLOCK_DELETED(b)	(((b) == 0) || ((b) == 0xfffffffe))
+
+#define BLOCK_TYPE(b)		((b) & 0x7f)
+#define BLOCK_ADDRESS(b)	((b) & ~0x7f)
+#define BLOCK_NUMBER(b)		((b) >> 9)
+#define BLOCK_CONTROL		0x30
+#define BLOCK_DATA		0x40
+#define BLOCK_REPLACEMENT	0x60
+#define BLOCK_BAD		0x70
+
+#endif /* _LINUX_FTL_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/mem_op.h linux/include/pcmcia/mem_op.h
--- v2.3.16/linux/include/pcmcia/mem_op.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/mem_op.h	Fri Sep  3 15:28:39 1999
@@ -0,0 +1,133 @@
+/*
+ * mem_op.h 1.10 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_MEM_OP_H
+#define _LINUX_MEM_OP_H
+
+#include <asm/uaccess.h>
+
+/*
+   If UNSAFE_MEMCPY is defined, we use the (optimized) system routines
+   to copy between a card and kernel memory.  These routines do 32-bit
+   operations which may not work with all PCMCIA controllers.  The
+   safe versions defined here will do only 8-bit and 16-bit accesses.
+*/
+
+#ifdef UNSAFE_MEMCPY
+
+#define copy_from_pc memcpy_fromio
+#define copy_to_pc memcpy_toio
+
+static inline void copy_pc_to_user(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 3);
+    n -= odd;
+    while (n) {
+	put_user(readl_ns(from), (int *)to);
+	(char *)from += 4; (char *)to += 4; n -= 4;
+    }
+    while (odd--)
+	put_user(readb((char *)from++), (char *)to++);
+}
+
+static inline void copy_user_to_pc(void *to, const void *from, size_t n)
+{
+    int l;
+    char c;
+    size_t odd = (n & 3);
+    n -= odd;
+    while (n) {
+	get_user(l, (int *)from);
+	writel_ns(l, to);
+	(char *)to += 4; (char *)from += 4; n -= 4;
+    }
+    while (odd--) {
+	get_user(c, (char *)from++);
+	writeb(c, (char *)to++);
+    }
+}
+
+#else /* UNSAFE_MEMCPY */
+
+static inline void copy_from_pc(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+	*(u_short *)to = __raw_readw(from);
+	(char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd)
+	*(u_char *)to = readb(from);
+}
+
+static inline void copy_to_pc(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+	__raw_writew(*(u_short *)from, to);
+	(char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd)
+	writeb(*(u_char *)from, to);
+}
+
+static inline void copy_pc_to_user(void *to, const void *from, size_t n)
+{
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+	put_user(__raw_readw(from), (short *)to);
+	(char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd)
+	put_user(readb(from), (char *)to);
+}
+
+static inline void copy_user_to_pc(void *to, const void *from, size_t n)
+{
+    short s;
+    char c;
+    size_t odd = (n & 1);
+    n -= odd;
+    while (n) {
+	get_user(s, (short *)from);
+	__raw_writew(s, to);
+	(char *)to += 2; (char *)from += 2; n -= 2;
+    }
+    if (odd) {
+	get_user(c, (char *)from);
+	writeb(c, to);
+    }
+}
+
+#endif /* UNSAFE_MEMCPY */
+
+#endif /* _LINUX_MEM_OP_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/memory.h linux/include/pcmcia/memory.h
--- v2.3.16/linux/include/pcmcia/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/memory.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,41 @@
+/*
+ * memory.h 1.5 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_MEMORY_H
+#define _LINUX_MEMORY_H
+
+typedef struct erase_info_t {
+    u_long	Offset;
+    u_long	Size;
+} erase_info_t;
+
+#define MEMGETINFO		_IOR('M', 1, region_info_t)
+#define MEMERASE		_IOW('M', 2, erase_info_t)
+
+#endif /* _LINUX_MEMORY_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/ss.h linux/include/pcmcia/ss.h
--- v2.3.16/linux/include/pcmcia/ss.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/ss.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,130 @@
+/*
+ * ss.h 1.24 1999/08/28 04:12:33
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License
+ * at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and
+ * limitations under the License. 
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Public License version 2 (the "GPL"), in which
+ * case the provisions of the GPL are applicable instead of the
+ * above.  If you wish to allow the use of your version of this file
+ * only under the terms of the GPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the GPL.  If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the GPL.
+ */
+
+#ifndef _LINUX_SS_H
+#define _LINUX_SS_H
+
+/* For RegisterCallback */
+typedef struct ss_callback_t {
+    void	(*handler)(void *info, u_int events);
+    void	*info;
+} ss_callback_t;
+
+/* Definitions for card status flags for GetStatus */
+#define SS_WRPROT	0x0001
+#define SS_CARDLOCK	0x0002
+#define SS_EJECTION	0x0004
+#define SS_INSERTION	0x0008
+#define SS_BATDEAD	0x0010
+#define SS_BATWARN	0x0020
+#define SS_READY	0x0040
+#define SS_DETECT	0x0080
+#define SS_POWERON	0x0100
+#define SS_GPI		0x0200
+#define SS_STSCHG	0x0400
+#define SS_CARDBUS	0x0800
+#define SS_3VCARD	0x1000
+#define SS_XVCARD	0x2000
+
+/* for InquireSocket */
+typedef struct socket_cap_t {
+    u_int	features;
+    u_int	irq_mask;
+    u_int	map_size;
+    u_char	pci_irq;
+    u_char	cardbus;
+    struct pci_bus *cb_bus;
+    struct bus_operations *bus;
+} socket_cap_t;
+
+/* InquireSocket capabilities */
+#define SS_CAP_PAGE_REGS	0x0001
+#define SS_CAP_VIRTUAL_BUS	0x0002
+#define SS_CAP_MEM_ALIGN	0x0004
+#define SS_CAP_PCCARD		0x4000
+#define SS_CAP_CARDBUS		0x8000
+
+/* for GetSocket, SetSocket */
+typedef struct socket_state_t {
+    u_int	flags;
+    u_int	csc_mask;
+    u_char	Vcc, Vpp;
+    u_char	io_irq;
+} socket_state_t;
+
+/* Socket configuration flags */
+#define SS_PWR_AUTO	0x0010
+#define SS_IOCARD	0x0020
+#define SS_RESET	0x0040
+#define SS_DMA_MODE	0x0080
+#define SS_SPKR_ENA	0x0100
+#define SS_OUTPUT_ENA	0x0200
+
+/* Flags for I/O port and memory windows */
+#define MAP_ACTIVE	0x01
+#define MAP_16BIT	0x02
+#define MAP_AUTOSZ	0x04
+#define MAP_0WS		0x08
+#define MAP_WRPROT	0x10
+#define MAP_ATTRIB	0x20
+#define MAP_USE_WAIT	0x40
+#define MAP_PREFETCH	0x80
+
+/* Use this just for bridge windows */
+#define MAP_IOSPACE	0x20
+
+typedef struct pccard_io_map {
+    u_char	map;
+    u_char	flags;
+    u_short	speed;
+    u_short	start, stop;
+} pccard_io_map;
+
+typedef struct pccard_mem_map {
+    u_char	map;
+    u_char	flags;
+    u_short	speed;
+    u_long	sys_start, sys_stop;
+    u_int	card_start;
+} pccard_mem_map;
+
+typedef struct cb_bridge_map {
+    u_char	map;
+    u_char	flags;
+    u_int	start, stop;
+} cb_bridge_map;
+
+enum ss_service {
+    SS_RegisterCallback, SS_InquireSocket,
+    SS_GetStatus, SS_GetSocket, SS_SetSocket,
+    SS_GetIOMap, SS_SetIOMap, SS_GetMemMap, SS_SetMemMap,
+    SS_GetBridge, SS_SetBridge, SS_ProcSetup
+};
+
+#endif /* _LINUX_SS_H */
diff -u --recursive --new-file v2.3.16/linux/include/pcmcia/version.h linux/include/pcmcia/version.h
--- v2.3.16/linux/include/pcmcia/version.h	Wed Dec 31 16:00:00 1969
+++ linux/include/pcmcia/version.h	Fri Sep  3 12:27:31 1999
@@ -0,0 +1,4 @@
+/* version.h 1.72 1999/08/05 06:09:53 (David Hinds) */
+
+#define CS_RELEASE "3.1.0"
+#define CS_RELEASE_CODE 0x3100
diff -u --recursive --new-file v2.3.16/linux/init/main.c linux/init/main.c
--- v2.3.16/linux/init/main.c	Tue Aug 31 17:29:15 1999
+++ linux/init/main.c	Fri Sep  3 22:06:48 1999
@@ -84,6 +84,7 @@
 extern void sysctl_init(void);
 extern void filescache_init(void);
 extern void signals_init(void);
+extern int pcmcia_init(void);
 
 extern void free_initmem(void);
 extern void filesystem_setup(void);
@@ -657,7 +658,9 @@
 #ifdef CONFIG_IRDA
 	irda_device_init(); /* Must be done after protocol initialization */
 #endif
-
+#ifdef CONFIG_PCMCIA
+	pcmcia_init();		/* Do this last */
+#endif
 	/* Mount the root filesystem.. */
 	mount_root();
 
diff -u --recursive --new-file v2.3.16/linux/ipc/shm.c linux/ipc/shm.c
--- v2.3.16/linux/ipc/shm.c	Tue Aug 31 17:29:15 1999
+++ linux/ipc/shm.c	Tue Sep  7 10:55:54 1999
@@ -372,7 +372,7 @@
  * shmd->vm_next	next attach for task
  * shmd->vm_next_share	next attach for segment
  * shmd->vm_offset	offset into segment
- * shmd->vm_pte		signature for this attach
+ * shmd->vm_private_data		signature for this attach
  */
 
 static struct vm_operations_struct shm_vm_ops = {
@@ -511,7 +511,7 @@
 		goto out;
 	}
 
-	shmd->vm_pte = SWP_ENTRY(SHM_SWP_TYPE, id);
+	shmd->vm_private_data = shm_segs + id;
 	shmd->vm_start = addr;
 	shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE;
 	shmd->vm_mm = current->mm;
@@ -547,16 +547,10 @@
 /* This is called by fork, once for every shm attach. */
 static void shm_open (struct vm_area_struct *shmd)
 {
-	unsigned int id;
 	struct shmid_kernel *shp;
 
 	lock_kernel();
-	id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
-	shp = shm_segs[id];
-	if (shp == IPC_UNUSED) {
-		printk("shm_open: unused id=%d PANIC\n", id);
-		return;
-	}
+	shp = *(struct shmid_kernel **) shmd->vm_private_data;
 	insert_attach(shp,shmd);  /* insert shmd into shp->attaches */
 	shp->u.shm_nattch++;
 	shp->u.shm_atime = CURRENT_TIME;
@@ -573,17 +567,17 @@
 static void shm_close (struct vm_area_struct *shmd)
 {
 	struct shmid_kernel *shp;
-	int id;
 
 	lock_kernel();
 	/* remove from the list of attaches of the shm segment */
-	id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
-	shp = shm_segs[id];
+	shp = *(struct shmid_kernel **) shmd->vm_private_data;
 	remove_attach(shp,shmd);  /* remove from shp->attaches */
   	shp->u.shm_lpid = current->pid;
 	shp->u.shm_dtime = CURRENT_TIME;
-	if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST)
+	if (--shp->u.shm_nattch <= 0 && shp->u.shm_perm.mode & SHM_DEST) {
+		unsigned int id = (struct shmid_kernel **)shmd->vm_private_data - shm_segs;
 		killseg (id);
+	}
 	unlock_kernel();
 }
 
@@ -628,20 +622,12 @@
 {
 	pte_t pte;
 	struct shmid_kernel *shp;
-	unsigned int id, idx;
+	unsigned int idx;
 	unsigned long page;
 	struct page * page_map;
 
-	id = SWP_OFFSET(shmd->vm_pte) & SHM_ID_MASK;
+	shp = *(struct shmid_kernel **) shmd->vm_private_data;
 	idx = (address - shmd->vm_start + shmd->vm_offset) >> PAGE_SHIFT;
-
-#ifdef DEBUG_SHM
-	if (id > max_shmid) {
-		printk ("shm_nopage: id=%d too big. proc mem corrupted\n", id);
-		return 0;
-	}
-#endif
-	shp = shm_segs[id];
 
 #ifdef DEBUG_SHM
 	if (shp == IPC_UNUSED || shp == IPC_NOID) {
diff -u --recursive --new-file v2.3.16/linux/kernel/exec_domain.c linux/kernel/exec_domain.c
--- v2.3.16/linux/kernel/exec_domain.c	Thu Aug 26 13:05:42 1999
+++ linux/kernel/exec_domain.c	Sat Sep  4 13:06:08 1999
@@ -2,7 +2,7 @@
 #include <linux/smp_lock.h>
 #include <linux/module.h>
 
-static asmlinkage void no_lcall7(struct pt_regs * regs);
+static asmlinkage void no_lcall7(int segment, struct pt_regs * regs);
 
 
 static unsigned long ident_map[32] = {
@@ -25,9 +25,8 @@
 static struct exec_domain *exec_domains = &default_exec_domain;
 
 
-static asmlinkage void no_lcall7(struct pt_regs * regs)
+static asmlinkage void no_lcall7(int segment, struct pt_regs * regs)
 {
-
   /*
    * This may have been a static linked SVr4 binary, so we would have the
    * personality set incorrectly.  Check to see whether SVr4 is available,
@@ -44,7 +43,7 @@
 
 	if (current->exec_domain && current->exec_domain->handler
 	&& current->exec_domain->handler != no_lcall7) {
-		current->exec_domain->handler(regs);
+		current->exec_domain->handler(segment, regs);
 		return;
 	}
 
diff -u --recursive --new-file v2.3.16/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.3.16/linux/kernel/ksyms.c	Tue Aug 31 17:29:15 1999
+++ linux/kernel/ksyms.c	Thu Sep  2 09:25:10 1999
@@ -320,6 +320,7 @@
 /* resource handling */
 EXPORT_SYMBOL(request_resource);
 EXPORT_SYMBOL(release_resource);
+EXPORT_SYMBOL(allocate_resource);
 EXPORT_SYMBOL(__request_region);
 EXPORT_SYMBOL(__check_region);
 EXPORT_SYMBOL(__release_region);
diff -u --recursive --new-file v2.3.16/linux/kernel/sys.c linux/kernel/sys.c
--- v2.3.16/linux/kernel/sys.c	Thu Aug 26 13:05:42 1999
+++ linux/kernel/sys.c	Sat Sep  4 13:10:35 1999
@@ -41,10 +41,6 @@
 	return notifier_chain_unregister(&reboot_notifier_list, nb);
 }
 
-
-
-extern void adjust_clock(void);
-
 asmlinkage long sys_ni_syscall(void)
 {
 	return -ENOSYS;
diff -u --recursive --new-file v2.3.16/linux/mm/filemap.c linux/mm/filemap.c
--- v2.3.16/linux/mm/filemap.c	Tue Aug 31 17:29:15 1999
+++ linux/mm/filemap.c	Wed Sep  1 14:10:09 1999
@@ -1303,7 +1303,7 @@
 	struct dentry * dentry = file->f_dentry;
 	struct inode * inode = dentry->d_inode;
 	struct page * page, **hash;
-	unsigned long old_page, new_page = 0;
+	unsigned long old_page;
 
 	unsigned long offset = address - area->vm_start + area->vm_offset;
 
@@ -1339,18 +1339,19 @@
 	 * and possibly copy it over to another page..
 	 */
 	old_page = page_address(page);
-	if (!no_share) {
-		flush_page_to_ram(old_page);
-		return old_page;
-	}
+	if (no_share) {
+		unsigned long new_page = page_cache_alloc();
 
-	new_page = page_cache_alloc();
-	if (new_page) {
-		copy_page(new_page, old_page);
-		flush_page_to_ram(new_page);
-	}
-	page_cache_release(page);
-	return new_page;
+		if (new_page) {
+			copy_page(new_page, old_page);
+			flush_page_to_ram(new_page);
+		}
+		page_cache_release(page);
+		return new_page;
+	}
+		
+	flush_page_to_ram(old_page);
+	return old_page;
 
 no_cached_page:
 	/*
@@ -1408,8 +1409,6 @@
 	 * mm layer so, possibly freeing the page cache page first.
 	 */
 	page_cache_release(page);
-	if (new_page)
-		page_cache_free(new_page);
 	return 0;
 }
 
diff -u --recursive --new-file v2.3.16/linux/mm/mmap.c linux/mm/mmap.c
--- v2.3.16/linux/mm/mmap.c	Thu Aug 26 13:05:42 1999
+++ linux/mm/mmap.c	Tue Sep  7 10:57:08 1999
@@ -275,7 +275,7 @@
 	vma->vm_ops = NULL;
 	vma->vm_offset = off;
 	vma->vm_file = NULL;
-	vma->vm_pte = 0;
+	vma->vm_private_data = NULL;
 
 	/* Clear old maps */
 	error = -ENOMEM;
@@ -547,7 +547,7 @@
 		mpnt->vm_ops = area->vm_ops;
 		mpnt->vm_offset = area->vm_offset + (end - area->vm_start);
 		mpnt->vm_file = area->vm_file;
-		mpnt->vm_pte = area->vm_pte;
+		mpnt->vm_private_data = area->vm_private_data;
 		if (mpnt->vm_file)
 			get_file(mpnt->vm_file);
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
@@ -778,7 +778,7 @@
 	vma->vm_ops = NULL;
 	vma->vm_offset = 0;
 	vma->vm_file = NULL;
-	vma->vm_pte = 0;
+	vma->vm_private_data = NULL;
 
 	/*
 	 * merge_segments may merge our vma, so we can't refer to it
@@ -920,7 +920,7 @@
 
 		/* To share, we must have the same file, operations.. */
 		if ((mpnt->vm_file != prev->vm_file)||
-		    (mpnt->vm_pte != prev->vm_pte)	||
+		    (mpnt->vm_private_data != prev->vm_private_data)	||
 		    (mpnt->vm_ops != prev->vm_ops)	||
 		    (mpnt->vm_flags != prev->vm_flags)	||
 		    (prev->vm_end != mpnt->vm_start))
diff -u --recursive --new-file v2.3.16/linux/net/README linux/net/README
--- v2.3.16/linux/net/README	Mon Apr 12 16:18:27 1999
+++ linux/net/README	Tue Sep  7 10:14:37 1999
@@ -13,6 +13,7 @@
 ipv4			davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
 ipv6			davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
 ipx/spx			Jay.Schulist@spacs.k12.wi.us
+irda                    dagb@cs.uit.no
 lapb			g4klx@g4klx.demon.co.uk
 netrom			g4klx@g4klx.demon.co.uk
 rose			g4klx@g4klx.demon.co.uk
diff -u --recursive --new-file v2.3.16/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.3.16/linux/net/appletalk/ddp.c	Thu Aug 26 13:05:42 1999
+++ linux/net/appletalk/ddp.c	Tue Sep  7 10:20:11 1999
@@ -1360,13 +1360,6 @@
 	return (0);
 }
 
-/*
- * Not relevant
- */
-static int atalk_accept(struct socket *sock, struct socket *newsock, int flags)
-{
-	return (-EOPNOTSUPP);
-}
 
 /*
  * Find the name of an AppleTalk socket. Just copy the right
@@ -1918,10 +1911,6 @@
 	return (err ? err : (copied));
 }
 
-static int atalk_shutdown(struct socket *sk,int how)
-{
-	return (-EOPNOTSUPP);
-}
 
 /*
  * AppleTalk ioctl calls.
@@ -2029,12 +2018,12 @@
 	atalk_bind,
 	atalk_connect,
 	sock_no_socketpair,
-	atalk_accept,
+	sock_no_accept,
 	atalk_getname,
 	datagram_poll,
 	atalk_ioctl,
 	sock_no_listen,
-	atalk_shutdown,
+	sock_no_shutdown,
 	sock_no_setsockopt,
 	sock_no_getsockopt,
 	sock_no_fcntl,
diff -u --recursive --new-file v2.3.16/linux/net/atm/pvc.c linux/net/atm/pvc.c
--- v2.3.16/linux/net/atm/pvc.c	Tue Aug 31 17:29:15 1999
+++ linux/net/atm/pvc.c	Tue Sep  7 10:20:11 1999
@@ -62,18 +62,6 @@
 }
 
 
-static int pvc_listen(struct socket *sock,int backlog)
-{
-	return -EOPNOTSUPP;
-}
-
-
-static int pvc_accept(struct socket *sock,struct socket *newsock,int flags)
-{
-	return -EOPNOTSUPP;
-}
-
-
 static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
     int *sockaddr_len,int peer)
 {
@@ -100,11 +88,11 @@
 	pvc_bind,
 	pvc_connect,
 	sock_no_socketpair,
-	pvc_accept,
+	sock_no_accept,
 	pvc_getname,
 	atm_poll,
 	atm_ioctl,
-	pvc_listen,
+	sock_no_listen,
 	pvc_shutdown,
 	atm_setsockopt,
 	atm_getsockopt,
diff -u --recursive --new-file v2.3.16/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.3.16/linux/net/core/iovec.c	Mon May 10 09:55:25 1999
+++ linux/net/core/iovec.c	Fri Sep  3 11:44:16 1999
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <net/checksum.h>
+#include <net/sock.h>
 
 /*
  *	Verify iovec. The caller must ensure that the iovec is big enough
diff -u --recursive --new-file v2.3.16/linux/net/decnet/af_decnet.c linux/net/decnet/af_decnet.c
--- v2.3.16/linux/net/decnet/af_decnet.c	Tue Aug 31 17:29:15 1999
+++ linux/net/decnet/af_decnet.c	Tue Sep  7 10:20:11 1999
@@ -1239,9 +1239,6 @@
 	if ((sk->protinfo.dn.state != DN_O) || (sk->state == TCP_LISTEN))
 		goto out;
 
-	if (backlog > SOMAXCONN)
-		backlog = SOMAXCONN;
-
 	sk->max_ack_backlog = backlog;
 	sk->ack_backlog     = 0;
 	sk->state           = TCP_LISTEN;
diff -u --recursive --new-file v2.3.16/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.3.16/linux/net/ipv4/af_inet.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipv4/af_inet.c	Tue Sep  7 10:20:11 1999
@@ -285,11 +285,6 @@
 	if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM)
 		return -EINVAL;
 
-	if ((unsigned) backlog == 0)	/* BSDism */
-		backlog = 1;
-	if ((unsigned) backlog > SOMAXCONN)
-		backlog = SOMAXCONN;
-
 	lock_sock(sk);
 	old_state = sk->state;
 	err = -EINVAL;
diff -u --recursive --new-file v2.3.16/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.3.16/linux/net/ipx/af_ipx.c	Tue Aug 31 17:29:15 1999
+++ linux/net/ipx/af_ipx.c	Tue Sep  7 10:20:11 1999
@@ -1983,10 +1983,6 @@
 	return (0);
 }
 
-static int ipx_accept(struct socket *sock, struct socket *newsock, int flags)
-{
-	return (-EOPNOTSUPP);
-}
 
 static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
 	int *uaddr_len, int peer)
@@ -2213,13 +2209,6 @@
 	return (err);
 }
 
-/*
- * FIXME: We have to really support shutdown.
- */
-static int ipx_shutdown(struct socket *sk,int how)
-{
-	return (-EOPNOTSUPP);
-}
 
 static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
 {
@@ -2342,12 +2331,12 @@
 	ipx_bind,
 	ipx_connect,
 	sock_no_socketpair,
-	ipx_accept,
+	sock_no_accept,
 	ipx_getname,
 	datagram_poll,
 	ipx_ioctl,
 	sock_no_listen,
-	ipx_shutdown,
+	sock_no_shutdown, /* FIXME: We have to really support shutdown. */
 	ipx_setsockopt,
 	ipx_getsockopt,
 	sock_no_fcntl,
diff -u --recursive --new-file v2.3.16/linux/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- v2.3.16/linux/net/ipx/af_spx.c	Thu Aug 26 13:05:46 1999
+++ linux/net/ipx/af_spx.c	Tue Sep  7 10:20:11 1999
@@ -113,10 +113,6 @@
 	return (0);
 }
 
-static int spx_shutdown(struct socket *sk,int how)
-{
-        return (-EOPNOTSUPP);
-}
 
 void spx_close_socket(struct sock *sk)
 {
@@ -184,10 +180,6 @@
         if(sk->zapped != 0)
                 return (-EAGAIN);
 
-        if((unsigned) backlog == 0)     /* BSDism */
-                backlog = 1;
-        if((unsigned) backlog > SOMAXCONN)
-                backlog = SOMAXCONN;
         sk->max_ack_backlog = backlog;
         if(sk->state != TCP_LISTEN)
         {
@@ -853,7 +845,7 @@
         datagram_poll,  /* this does seqpacket too */
 	spx_ioctl,
         spx_listen,
-        spx_shutdown,
+        sock_no_shutdown,
 	spx_setsockopt,
 	spx_getsockopt,
         sock_no_fcntl,
diff -u --recursive --new-file v2.3.16/linux/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- v2.3.16/linux/net/irda/irlmp_event.c	Tue Aug 31 17:29:15 1999
+++ linux/net/irda/irlmp_event.c	Tue Sep  7 10:14:37 1999
@@ -347,16 +347,17 @@
 		 *  must be the one that tries to close IrLAP. It will be 
 		 *  removed later and moved to the list of unconnected LSAPs
 		 */
-		if (hashbin_get_size(self->lsaps) == 1)
+		if (hashbin_get_size(self->lsaps) > 0)
 			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
-
+		else {
+			/* No more connections, so close IrLAP */
+			irlmp_next_lap_state(self, LAP_STANDBY);
+			irlap_disconnect_request(self->irlap);
+		}
 		break;
 	case LM_LAP_IDLE_TIMEOUT:
 		if (hashbin_get_size(self->lsaps) == 0) {
-			DEBUG(2, __FUNCTION__ 
-			      "(), no more LSAPs so time to close IrLAP\n");
 			irlmp_next_lap_state(self, LAP_STANDBY);
-			
 			irlap_disconnect_request(self->irlap);
 		} else
 			/* Still not ready, so wait a little bit more */
diff -u --recursive --new-file v2.3.16/linux/net/khttpd/misc.c linux/net/khttpd/misc.c
--- v2.3.16/linux/net/khttpd/misc.c	Thu Aug 26 13:05:46 1999
+++ linux/net/khttpd/misc.c	Thu Sep  2 11:47:20 1999
@@ -214,9 +214,9 @@
 
 */
 
-static char NoPerm[] = "403 Permission denied\r\nServer: kHTTPd 0.1.6\r\n\r\n Permission denied";
-static char TryLater[] = "500 Try again later\r\nServer: kHTTPd 0.1.6\r\n\r\n Try again later";
-static char NotModified[] = "304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n";
+static char NoPerm[] = "HTTP/1.0 403 Forbidden\r\nServer: kHTTPd 0.1.6\r\n\r\n";
+static char TryLater[] = "HTTP/1.0 503 Service Unavailable\r\nServer: kHTTPd 0.1.6\r\nContent-Length: 15\r\n\r\nTry again later";
+static char NotModified[] = "HTTP/1.0 304 Not Modified\r\nServer: kHTTPd 0.1.6\r\n\r\n";
 
 
 void Send403(struct socket *sock)
@@ -229,7 +229,7 @@
 void Send304(struct socket *sock)
 {
 	EnterFunction("Send304");
-	(void)SendBuffer(sock,NotModified,strlen(NoPerm));
+	(void)SendBuffer(sock,NotModified,strlen(NotModified));
 	LeaveFunction("Send304");
 }
 
diff -u --recursive --new-file v2.3.16/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.3.16/linux/net/netrom/af_netrom.c	Tue Aug 31 17:29:15 1999
+++ linux/net/netrom/af_netrom.c	Tue Sep  7 10:20:11 1999
@@ -1100,10 +1100,6 @@
 	return copied;
 }
 
-static int nr_shutdown(struct socket *sk, int how)
-{
-	return -EOPNOTSUPP;
-}
 
 static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
@@ -1255,7 +1251,7 @@
 	datagram_poll,
 	nr_ioctl,
 	nr_listen,
-	nr_shutdown,
+	sock_no_shutdown,
 	nr_setsockopt,
 	nr_getsockopt,
 	sock_no_fcntl,
diff -u --recursive --new-file v2.3.16/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.3.16/linux/net/rose/af_rose.c	Tue Aug 31 17:29:15 1999
+++ linux/net/rose/af_rose.c	Tue Sep  7 10:20:11 1999
@@ -1245,10 +1245,6 @@
 	return copied;
 }
 
-static int rose_shutdown(struct socket *sk, int how)
-{
-	return -EOPNOTSUPP;
-}
 
 static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
@@ -1445,7 +1441,7 @@
 	datagram_poll,
 	rose_ioctl,
 	rose_listen,
-	rose_shutdown,
+	sock_no_shutdown,
 	rose_setsockopt,
 	rose_getsockopt,
 	sock_no_fcntl,
diff -u --recursive --new-file v2.3.16/linux/net/socket.c linux/net/socket.c
--- v2.3.16/linux/net/socket.c	Thu Aug 26 13:05:46 1999
+++ linux/net/socket.c	Tue Sep  7 10:20:11 1999
@@ -42,6 +42,8 @@
  *		Andi Kleen	:	Some small cleanups, optimizations,
  *					and fixed a copy_from_user() bug.
  *		Tigran Aivazian	:	sys_send(args) calls sys_sendto(args, NULL, 0)
+ *		Tigran Aivazian	:	Made listen(2) backlog sanity checks 
+ *					protocol-independent
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -894,6 +896,10 @@
 	int err;
 	
 	if ((sock = sockfd_lookup(fd, &err)) != NULL) {
+		if ((unsigned) backlog == 0)	/* BSDism */
+			backlog = 1;
+		if ((unsigned) backlog > SOMAXCONN)
+			backlog = SOMAXCONN;
 		err=sock->ops->listen(sock, backlog);
 		sockfd_put(sock);
 	}
diff -u --recursive --new-file v2.3.16/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.3.16/linux/net/unix/af_unix.c	Tue Aug 31 17:29:15 1999
+++ linux/net/unix/af_unix.c	Tue Sep  7 10:20:11 1999
@@ -414,8 +414,6 @@
 	err = -EINVAL;
 	if (!sk->protinfo.af_unix.addr)
 		goto out;			/* No listens on an unbound socket */
-	if ((unsigned) backlog > SOMAXCONN)
-		backlog = SOMAXCONN;
 	unix_state_wlock(sk);
 	if (sk->state != TCP_CLOSE && sk->state != TCP_LISTEN)
 		goto out_unlock;
diff -u --recursive --new-file v2.3.16/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.3.16/linux/net/x25/af_x25.c	Tue Aug 31 17:29:15 1999
+++ linux/net/x25/af_x25.c	Tue Sep  7 10:20:11 1999
@@ -1044,10 +1044,6 @@
 	return copied;
 }
 
-static int x25_shutdown(struct socket *sk, int how)
-{
-	return -EOPNOTSUPP;
-}
 
 static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
@@ -1246,7 +1242,7 @@
 	datagram_poll,
 	x25_ioctl,
 	x25_listen,
-	x25_shutdown,
+	sock_no_shutdown,
 	x25_setsockopt,
 	x25_getsockopt,
 	sock_no_fcntl,
